@@ -6,7 +6,7 @@ use num_bigint::BigInt;
66use serde:: { Deserialize , Serialize } ;
77
88/// Data representation of on-chain data such as Datums and Redeemers
9- #[ derive( Debug , PartialEq , Eq ) ]
9+ #[ derive( Debug , PartialEq , Eq , Clone ) ]
1010#[ cfg_attr( feature = "lbf" , derive( Json ) ) ]
1111#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
1212pub enum PlutusData {
@@ -16,3 +16,291 @@ pub enum PlutusData {
1616 Integer ( BigInt ) ,
1717 Bytes ( Vec < u8 > ) ,
1818}
19+
20+ pub trait ToPlutusData {
21+ fn to_plutus_data ( & self ) -> PlutusData ;
22+ }
23+
24+ pub trait FromPlutusData {
25+ fn from_plutus_data ( plutus_data : PlutusData ) -> Result < Self , PlutusDataError >
26+ where
27+ Self : Sized ;
28+ }
29+
30+ #[ derive( Debug , Clone ) ]
31+ pub enum PlutusType {
32+ Constr ,
33+ Map ,
34+ List ,
35+ Integer ,
36+ Bytes ,
37+ }
38+
39+ impl From < & PlutusData > for PlutusType {
40+ fn from ( plutus_data : & PlutusData ) -> Self {
41+ match plutus_data {
42+ PlutusData :: Constr ( _, _) => PlutusType :: Constr ,
43+ PlutusData :: Map ( _) => PlutusType :: Map ,
44+ PlutusData :: List ( _) => PlutusType :: List ,
45+ PlutusData :: Integer ( _) => PlutusType :: Integer ,
46+ PlutusData :: Bytes ( _) => PlutusType :: Bytes ,
47+ }
48+ }
49+ }
50+
51+ #[ derive( thiserror:: Error , Debug ) ]
52+ pub enum PlutusDataError {
53+ #[ error( "Expected a PlutusData type {wanted:?}, but got {got:?}" ) ]
54+ UnexpectedPlutusType { got : PlutusType , wanted : PlutusType } ,
55+ #[ error( "Expected a PlutusData type as {wanted:?}, but got {got:?}" ) ]
56+ UnexpectedPlutusInvariant { got : String , wanted : String } ,
57+ #[ error( "Expected a Plutus List with {wanted:?} elements, but got {got:?} elements" ) ]
58+ UnexpectedListLength { got : usize , wanted : usize } ,
59+ #[ error( "Some internal error happened: {0}" ) ]
60+ InternalError ( String ) ,
61+ }
62+
63+ impl ToPlutusData for BigInt {
64+ fn to_plutus_data ( & self ) -> PlutusData {
65+ PlutusData :: Integer ( self . clone ( ) )
66+ }
67+ }
68+
69+ impl FromPlutusData for BigInt {
70+ fn from_plutus_data ( plutus_data : PlutusData ) -> Result < Self , PlutusDataError > {
71+ match plutus_data {
72+ PlutusData :: Integer ( int) => Ok ( int) ,
73+ _ => Err ( PlutusDataError :: UnexpectedPlutusType {
74+ wanted : PlutusType :: Integer ,
75+ got : PlutusType :: from ( & plutus_data) ,
76+ } ) ,
77+ }
78+ }
79+ }
80+
81+ impl ToPlutusData for bool {
82+ fn to_plutus_data ( & self ) -> PlutusData {
83+ if * self {
84+ PlutusData :: Constr ( BigInt :: from ( 1 ) , Vec :: with_capacity ( 0 ) )
85+ } else {
86+ PlutusData :: Constr ( BigInt :: from ( 0 ) , Vec :: with_capacity ( 0 ) )
87+ }
88+ }
89+ }
90+
91+ impl FromPlutusData for bool {
92+ fn from_plutus_data ( plutus_data : PlutusData ) -> Result < Self , PlutusDataError > {
93+ match plutus_data {
94+ PlutusData :: Constr ( flag, fields) => match u32:: try_from ( & flag) {
95+ Ok ( 0 ) => {
96+ verify_fields_len ( & fields, 0 ) ?;
97+ Ok ( false )
98+ }
99+ Ok ( 1 ) => {
100+ verify_fields_len ( & fields, 0 ) ?;
101+ Ok ( true )
102+ }
103+ _ => Err ( PlutusDataError :: UnexpectedPlutusInvariant {
104+ wanted : "Constr field between 0 and 1" . to_owned ( ) ,
105+ got : flag. to_string ( ) ,
106+ } ) ,
107+ } ,
108+
109+ _ => Err ( PlutusDataError :: UnexpectedPlutusType {
110+ wanted : PlutusType :: Constr ,
111+ got : PlutusType :: from ( & plutus_data) ,
112+ } ) ,
113+ }
114+ }
115+ }
116+
117+ impl ToPlutusData for char {
118+ fn to_plutus_data ( & self ) -> PlutusData {
119+ String :: from ( * self ) . to_plutus_data ( )
120+ }
121+ }
122+
123+ impl FromPlutusData for char {
124+ fn from_plutus_data ( plutus_data : PlutusData ) -> Result < Self , PlutusDataError > {
125+ String :: from_plutus_data ( plutus_data) . and_then ( |str| {
126+ let mut chars = str. chars ( ) ;
127+ let ch = chars. next ( ) ;
128+ let rest = chars. next ( ) ;
129+ match ( ch, rest) {
130+ ( Some ( ch) , None ) => Ok ( ch) ,
131+ _ => Err ( PlutusDataError :: UnexpectedPlutusInvariant {
132+ got : "string" . to_owned ( ) ,
133+ wanted : "char" . to_owned ( ) ,
134+ } ) ,
135+ }
136+ } )
137+ }
138+ }
139+
140+ impl ToPlutusData for Vec < u8 > {
141+ fn to_plutus_data ( & self ) -> PlutusData {
142+ PlutusData :: Bytes ( self . clone ( ) )
143+ }
144+ }
145+
146+ impl FromPlutusData for Vec < u8 > {
147+ fn from_plutus_data ( plutus_data : PlutusData ) -> Result < Self , PlutusDataError > {
148+ match plutus_data {
149+ PlutusData :: Bytes ( bytes) => Ok ( bytes) ,
150+ _ => Err ( PlutusDataError :: UnexpectedPlutusType {
151+ wanted : PlutusType :: Bytes ,
152+ got : PlutusType :: from ( & plutus_data) ,
153+ } ) ,
154+ }
155+ }
156+ }
157+
158+ impl ToPlutusData for String {
159+ fn to_plutus_data ( & self ) -> PlutusData {
160+ PlutusData :: Bytes ( self . as_bytes ( ) . into ( ) )
161+ }
162+ }
163+
164+ impl FromPlutusData for String {
165+ fn from_plutus_data ( plutus_data : PlutusData ) -> Result < Self , PlutusDataError > {
166+ match plutus_data {
167+ PlutusData :: Bytes ( bytes) => String :: from_utf8 ( bytes) . map_err ( |err| {
168+ PlutusDataError :: InternalError ( format ! (
169+ "Couldn't convert Plutus bytes to String: {:?}" ,
170+ err
171+ ) )
172+ } ) ,
173+ _ => Err ( PlutusDataError :: UnexpectedPlutusType {
174+ wanted : PlutusType :: Integer ,
175+ got : PlutusType :: from ( & plutus_data) ,
176+ } ) ,
177+ }
178+ }
179+ }
180+
181+ impl < T > ToPlutusData for Option < T >
182+ where
183+ T : ToPlutusData ,
184+ {
185+ fn to_plutus_data ( & self ) -> PlutusData {
186+ match self {
187+ Some ( val) => PlutusData :: Constr ( BigInt :: from ( 0 ) , vec ! [ val. to_plutus_data( ) ] ) ,
188+ None => PlutusData :: Constr ( BigInt :: from ( 1 ) , Vec :: with_capacity ( 0 ) ) ,
189+ }
190+ }
191+ }
192+
193+ impl < T > FromPlutusData for Option < T >
194+ where
195+ T : FromPlutusData ,
196+ {
197+ fn from_plutus_data ( plutus_data : PlutusData ) -> Result < Self , PlutusDataError > {
198+ match plutus_data {
199+ PlutusData :: Constr ( flag, fields) => match u32:: try_from ( & flag) {
200+ Ok ( 0 ) => {
201+ verify_fields_len ( & fields, 1 ) ?;
202+ Ok ( Some ( T :: from_plutus_data ( fields[ 0 ] . clone ( ) ) ?) )
203+ }
204+ Ok ( 1 ) => {
205+ verify_fields_len ( & fields, 0 ) ?;
206+ Ok ( None )
207+ }
208+ _ => Err ( PlutusDataError :: UnexpectedPlutusInvariant {
209+ wanted : "Constr field between 0 and 1" . to_owned ( ) ,
210+ got : flag. to_string ( ) ,
211+ } ) ,
212+ } ,
213+
214+ _ => Err ( PlutusDataError :: UnexpectedPlutusType {
215+ wanted : PlutusType :: Constr ,
216+ got : PlutusType :: from ( & plutus_data) ,
217+ } ) ,
218+ }
219+ }
220+ }
221+
222+ impl < T , E > ToPlutusData for Result < T , E >
223+ where
224+ T : ToPlutusData ,
225+ E : ToPlutusData ,
226+ {
227+ fn to_plutus_data ( & self ) -> PlutusData {
228+ match self {
229+ Err ( val) => PlutusData :: Constr ( BigInt :: from ( 0 ) , vec ! [ val. to_plutus_data( ) ] ) ,
230+ Ok ( val) => PlutusData :: Constr ( BigInt :: from ( 1 ) , vec ! [ val. to_plutus_data( ) ] ) ,
231+ }
232+ }
233+ }
234+
235+ impl < T , E > FromPlutusData for Result < T , E >
236+ where
237+ T : FromPlutusData ,
238+ E : FromPlutusData ,
239+ {
240+ fn from_plutus_data ( plutus_data : PlutusData ) -> Result < Self , PlutusDataError > {
241+ match plutus_data {
242+ PlutusData :: Constr ( flag, fields) => match u32:: try_from ( & flag) {
243+ Ok ( 0 ) => {
244+ verify_fields_len ( & fields, 1 ) ?;
245+ Ok ( Err ( E :: from_plutus_data ( fields[ 0 ] . clone ( ) ) ?) )
246+ }
247+ Ok ( 1 ) => {
248+ verify_fields_len ( & fields, 1 ) ?;
249+ Ok ( Ok ( T :: from_plutus_data ( fields[ 0 ] . clone ( ) ) ?) )
250+ }
251+ _ => Err ( PlutusDataError :: UnexpectedPlutusInvariant {
252+ wanted : "Constr field between 0 and 1" . to_owned ( ) ,
253+ got : flag. to_string ( ) ,
254+ } ) ,
255+ } ,
256+
257+ _ => Err ( PlutusDataError :: UnexpectedPlutusType {
258+ wanted : PlutusType :: Constr ,
259+ got : PlutusType :: from ( & plutus_data) ,
260+ } ) ,
261+ }
262+ }
263+ }
264+
265+ impl < T > ToPlutusData for Vec < T >
266+ where
267+ T : ToPlutusData ,
268+ {
269+ fn to_plutus_data ( & self ) -> PlutusData {
270+ let values = self
271+ . iter ( )
272+ . map ( |val| val. to_plutus_data ( ) )
273+ . collect :: < Vec < PlutusData > > ( ) ;
274+
275+ PlutusData :: List ( values)
276+ }
277+ }
278+
279+ impl < T > FromPlutusData for Vec < T >
280+ where
281+ T : FromPlutusData ,
282+ {
283+ fn from_plutus_data ( plutus_data : PlutusData ) -> Result < Self , PlutusDataError > {
284+ match plutus_data {
285+ PlutusData :: List ( vec) => vec
286+ . iter ( )
287+ . map ( |val| T :: from_plutus_data ( val. clone ( ) ) )
288+ . collect :: < Result < Vec < T > , PlutusDataError > > ( ) ,
289+ _ => Err ( PlutusDataError :: UnexpectedPlutusType {
290+ wanted : PlutusType :: List ,
291+ got : PlutusType :: from ( & plutus_data) ,
292+ } ) ,
293+ }
294+ }
295+ }
296+
297+ fn verify_fields_len ( fields : & Vec < PlutusData > , expected : usize ) -> Result < ( ) , PlutusDataError > {
298+ if fields. len ( ) != expected {
299+ Err ( PlutusDataError :: UnexpectedPlutusInvariant {
300+ wanted : format ! ( "Constr with {} fields" , expected) ,
301+ got : format ! ( "{:?}" , fields) ,
302+ } )
303+ } else {
304+ Ok ( ( ) )
305+ }
306+ }
0 commit comments