1mod primitives;
2
3#[cfg(feature = "derive")]
4pub use plutus_parser_derive::*;
5
6#[cfg(feature = "pallas-v0_32")]
7pub use minicbor_v0_25 as minicbor;
8#[cfg(feature = "pallas-v0_32")]
9pub use pallas_v0_32::{
10 BigInt, BoundedBytes, Constr, Int, KeyValuePairs, MaybeIndefArray, PlutusData,
11};
12
13#[cfg(feature = "pallas-v0_33")]
14pub use minicbor_v0_25 as minicbor;
15#[cfg(feature = "pallas-v0_33")]
16pub use pallas_v0_33::{
17 BigInt, BoundedBytes, Constr, Int, KeyValuePairs, MaybeIndefArray, PlutusData,
18};
19
20#[cfg(feature = "pallas-v0_34")]
21pub use minicbor_v0_25 as minicbor;
22#[cfg(feature = "pallas-v0_34")]
23pub use pallas_v0_34::{
24 BigInt, BoundedBytes, Constr, Int, KeyValuePairs, MaybeIndefArray, PlutusData,
25};
26
27#[cfg(feature = "pallas-v1")]
28pub use minicbor_v0_26 as minicbor;
29#[cfg(feature = "pallas-v1")]
30pub use pallas_v1::{
31 BigInt, BoundedBytes, Constr, Int, KeyValuePairs, MaybeIndefArray, PlutusData,
32};
33
34use thiserror::Error;
35
36#[derive(Error, Debug)]
37pub enum DecodeError {
38 #[error("unexpected variant {variant}")]
39 UnexpectedVariant { variant: u64 },
40 #[error("unexpected type (expected {expected}, found {actual})")]
41 UnexpectedType { expected: String, actual: String },
42 #[error("unexpected field count for tuple (expected {expected}, found {actual})")]
43 WrongTupleFieldCount { expected: usize, actual: usize },
44 #[error("unexpected field count for variant {variant} (expected {expected}, found {actual})")]
45 WrongVariantFieldCount {
46 variant: u64,
47 expected: usize,
48 actual: usize,
49 },
50 #[error("invalid cbor: {0}")]
51 InvalidCbor(minicbor::decode::Error),
52 #[error("{0}")]
53 Custom(String),
54}
55
56pub trait AsPlutus: Sized {
57 fn from_plutus(data: PlutusData) -> Result<Self, DecodeError>;
58 fn to_plutus(self) -> PlutusData;
59
60 fn from_plutus_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
61 let data = minicbor::decode::<PlutusData>(bytes).map_err(DecodeError::InvalidCbor)?;
62 Self::from_plutus(data)
63 }
64
65 fn to_plutus_bytes(self) -> Vec<u8> {
66 let data = self.to_plutus();
67 minicbor::to_vec(data).expect("infallible")
68 }
69
70 fn vec_from_plutus(data: PlutusData) -> Result<Vec<Self>, DecodeError> {
71 let items = parse_array(data)?;
72 items.into_iter().map(Self::from_plutus).collect()
73 }
74
75 fn vec_to_plutus(value: Vec<Self>) -> PlutusData {
76 create_array(value.into_iter().map(Self::to_plutus).collect())
77 }
78}
79
80pub fn parse_array(data: PlutusData) -> Result<Vec<PlutusData>, DecodeError> {
81 let array = match data {
82 PlutusData::Array(array) => array,
83 other => {
84 return Err(DecodeError::UnexpectedType {
85 expected: "Array".to_string(),
86 actual: type_name(&other),
87 });
88 }
89 };
90 Ok(array.to_vec())
91}
92
93pub fn parse_tuple<const N: usize>(data: PlutusData) -> Result<[PlutusData; N], DecodeError> {
94 let array = parse_array(data)?;
95 array
96 .try_into()
97 .map_err(|f: Vec<PlutusData>| DecodeError::WrongTupleFieldCount {
98 expected: N,
99 actual: f.len(),
100 })
101}
102
103pub fn parse_constr(data: PlutusData) -> Result<(u64, Vec<PlutusData>), DecodeError> {
104 let constr = match data {
105 PlutusData::Constr(constr) => constr,
106 other => {
107 return Err(DecodeError::UnexpectedType {
108 expected: "Constr".to_string(),
109 actual: type_name(&other),
110 });
111 }
112 };
113 let Some(variant) = constr.constructor_value() else {
114 return Err(DecodeError::Custom("value has invalid tag".to_string()));
115 };
116 Ok((variant, constr.fields.to_vec()))
117}
118
119pub fn parse_variant<const N: usize>(
120 variant: u64,
121 fields: Vec<PlutusData>,
122) -> Result<[PlutusData; N], DecodeError> {
123 fields
124 .try_into()
125 .map_err(|f: Vec<PlutusData>| DecodeError::WrongVariantFieldCount {
126 variant,
127 expected: N,
128 actual: f.len(),
129 })
130}
131
132pub fn parse_map(data: PlutusData) -> Result<Vec<(PlutusData, PlutusData)>, DecodeError> {
133 let kvps = match data {
134 PlutusData::Map(kvps) => kvps,
135 other => {
136 return Err(DecodeError::UnexpectedType {
137 expected: "Map".to_string(),
138 actual: type_name(&other),
139 });
140 }
141 };
142 Ok(kvps.to_vec())
143}
144
145pub fn create_constr(variant: u64, fields: Vec<PlutusData>) -> PlutusData {
146 let (tag, any_constructor) = match variant {
147 0..=6 => (variant + 121, None),
148 7..=127 => (variant + 1280 - 7, None),
149 x => (102, Some(x)),
150 };
151 PlutusData::Constr(Constr {
152 tag,
153 any_constructor,
154 fields: if !fields.is_empty() {
155 MaybeIndefArray::Indef(fields)
156 } else {
157 MaybeIndefArray::Def(Vec::new())
158 },
159 })
160}
161
162pub fn create_array(fields: Vec<PlutusData>) -> PlutusData {
163 PlutusData::Array(if !fields.is_empty() {
164 MaybeIndefArray::Indef(fields)
165 } else {
166 MaybeIndefArray::Def(Vec::new())
167 })
168}
169
170pub fn create_map(kvps: Vec<(PlutusData, PlutusData)>) -> PlutusData {
171 PlutusData::Map(KeyValuePairs::Def(kvps))
172}
173
174pub(crate) fn type_name(data: &PlutusData) -> String {
175 match data {
176 PlutusData::Array(_) => "Array",
177 PlutusData::BigInt(_) => "BigInt",
178 PlutusData::BoundedBytes(_) => "BoundedBytes",
179 PlutusData::Constr(_) => "Constr",
180 PlutusData::Map(_) => "Map",
181 }
182 .to_string()
183}