1
1
//! Plutus Data related types and traits
2
2
#[ cfg( feature = "lbf" ) ]
3
- use lbr_prelude:: json:: Json ;
3
+ use data_encoding:: HEXLOWER ;
4
+ #[ cfg( feature = "lbf" ) ]
5
+ use lbr_prelude:: error:: Error ;
6
+ #[ cfg( feature = "lbf" ) ]
7
+ use lbr_prelude:: json:: {
8
+ case_json_constructor, case_json_object, json_constructor, json_object, Json ,
9
+ } ;
4
10
use num_bigint:: BigInt ;
5
11
use std:: collections:: { BTreeMap , BTreeSet } ;
6
12
@@ -9,7 +15,6 @@ use serde::{Deserialize, Serialize};
9
15
10
16
/// Data representation of on-chain data such as Datums and Redeemers
11
17
#[ derive( Clone , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
12
- #[ cfg_attr( feature = "lbf" , derive( Json ) ) ]
13
18
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
14
19
pub enum PlutusData {
15
20
Constr ( BigInt , Vec < PlutusData > ) ,
@@ -41,6 +46,122 @@ impl PlutusData {
41
46
}
42
47
}
43
48
49
+ #[ cfg( feature = "lbf" ) ]
50
+ impl Json for PlutusData {
51
+ fn to_json ( & self ) -> serde_json:: Value {
52
+ match self {
53
+ PlutusData :: Constr ( index, fields) => json_constructor (
54
+ "Constr" ,
55
+ vec ! [ json_object( vec![
56
+ ( "index" . to_string( ) , index. to_json( ) ) ,
57
+ ( "fields" . to_string( ) , fields. to_json( ) ) ,
58
+ ] ) ] ,
59
+ ) ,
60
+ PlutusData :: Map ( map) => json_constructor ( "Map" , vec ! [ map. to_json( ) ] ) ,
61
+ PlutusData :: List ( list) => json_constructor ( "List" , vec ! [ list. to_json( ) ] ) ,
62
+ PlutusData :: Integer ( int) => json_constructor ( "Integer" , vec ! [ int. to_json( ) ] ) ,
63
+ PlutusData :: Bytes ( bytes) => {
64
+ json_constructor ( "Bytes" , vec ! [ String :: to_json( & HEXLOWER . encode( bytes) ) ] )
65
+ }
66
+ }
67
+ }
68
+
69
+ fn from_json ( value : & serde_json:: Value ) -> Result < PlutusData , Error > {
70
+ case_json_constructor (
71
+ "PlutusV1.PlutusData" ,
72
+ vec ! [
73
+ (
74
+ "Constr" ,
75
+ Box :: new( |ctor_fields| match & ctor_fields[ ..] {
76
+ [ val] => case_json_object(
77
+ |obj| {
78
+ let index = obj. get( "index" ) . ok_or( Error :: UnexpectedFieldName {
79
+ wanted: "index" . to_owned( ) ,
80
+ got: obj. keys( ) . cloned( ) . collect( ) ,
81
+ parser: "PlutusV1.PlutusData" . to_owned( ) ,
82
+ } ) ?;
83
+
84
+ let fields =
85
+ obj. get( "fields" ) . ok_or( Error :: UnexpectedFieldName {
86
+ wanted: "fields" . to_owned( ) ,
87
+ got: obj. keys( ) . cloned( ) . collect( ) ,
88
+ parser: "PlutusV1.PlutusData" . to_owned( ) ,
89
+ } ) ?;
90
+ Ok ( PlutusData :: Constr (
91
+ BigInt :: from_json( index) ?,
92
+ <Vec <PlutusData >>:: from_json( fields) ?,
93
+ ) )
94
+ } ,
95
+ val,
96
+ ) ,
97
+ _ => Err ( Error :: UnexpectedArrayLength {
98
+ wanted: 1 ,
99
+ got: ctor_fields. len( ) ,
100
+ parser: "PlutusV1.PlutusData" . to_owned( ) ,
101
+ } ) ,
102
+ } ) ,
103
+ ) ,
104
+ (
105
+ "Map" ,
106
+ Box :: new( |ctor_fields| match & ctor_fields[ ..] {
107
+ [ val] => Ok ( PlutusData :: Map ( Json :: from_json( val) ?) ) ,
108
+ _ => Err ( Error :: UnexpectedArrayLength {
109
+ wanted: 1 ,
110
+ got: ctor_fields. len( ) ,
111
+ parser: "PlutusV1.PlutusData" . to_owned( ) ,
112
+ } ) ,
113
+ } ) ,
114
+ ) ,
115
+ (
116
+ "List" ,
117
+ Box :: new( |ctor_fields| match & ctor_fields[ ..] {
118
+ [ val] => Ok ( PlutusData :: List ( Json :: from_json( val) ?) ) ,
119
+ _ => Err ( Error :: UnexpectedArrayLength {
120
+ wanted: 1 ,
121
+ got: ctor_fields. len( ) ,
122
+ parser: "PlutusV1.PlutusData" . to_owned( ) ,
123
+ } ) ,
124
+ } ) ,
125
+ ) ,
126
+ (
127
+ "Integer" ,
128
+ Box :: new( |ctor_fields| match & ctor_fields[ ..] {
129
+ [ val] => Ok ( PlutusData :: Integer ( Json :: from_json( val) ?) ) ,
130
+ _ => Err ( Error :: UnexpectedArrayLength {
131
+ wanted: 1 ,
132
+ got: ctor_fields. len( ) ,
133
+ parser: "PlutusV1.PlutusData" . to_owned( ) ,
134
+ } ) ,
135
+ } ) ,
136
+ ) ,
137
+ (
138
+ "Bytes" ,
139
+ Box :: new( |ctor_fields| match & ctor_fields[ ..] {
140
+ [ val] => {
141
+ let bytes = String :: from_json( val) . and_then( |str | {
142
+ HEXLOWER . decode( & str . into_bytes( ) ) . map_err( |_| {
143
+ Error :: UnexpectedJsonInvariant {
144
+ wanted: "base16 string" . to_owned( ) ,
145
+ got: "unexpected string" . to_owned( ) ,
146
+ parser: "Plutus.V1.Bytes" . to_owned( ) ,
147
+ }
148
+ } )
149
+ } ) ?;
150
+ Ok ( PlutusData :: Bytes ( bytes) )
151
+ }
152
+ _ => Err ( Error :: UnexpectedArrayLength {
153
+ wanted: 1 ,
154
+ got: ctor_fields. len( ) ,
155
+ parser: "PlutusV1.PlutusData" . to_owned( ) ,
156
+ } ) ,
157
+ } ) ,
158
+ ) ,
159
+ ] ,
160
+ value,
161
+ )
162
+ }
163
+ }
164
+
44
165
/// Deserialise a Plutus data using parsers for each variant
45
166
pub fn case_plutus_data < ' a , T > (
46
167
ctor_case : impl FnOnce ( & ' a BigInt ) -> Box < dyn ' a + FnOnce ( & ' a Vec < PlutusData > ) -> T > ,
0 commit comments