plutus_ledger_api/
plutus_data.rs

1//! Plutus Data related types and traits
2
3use std::collections::{BTreeMap, BTreeSet};
4
5use cardano_serialization_lib as csl;
6use num_bigint::BigInt;
7
8use crate::csl::csl_to_pla::{FromCSL, TryFromCSL, TryFromCSLError, TryToPLA};
9use crate::csl::pla_to_csl::{TryFromPLA, TryFromPLAError, TryToCSL};
10
11pub use is_plutus_data_derive::IsPlutusData;
12
13#[cfg(feature = "lbf")]
14use data_encoding::HEXLOWER;
15#[cfg(feature = "lbf")]
16use lbr_prelude::error::Error;
17#[cfg(feature = "lbf")]
18use lbr_prelude::json::{
19    case_json_constructor, case_json_object, json_constructor, json_object, Json,
20};
21
22#[cfg(feature = "serde")]
23use serde::{Deserialize, Serialize};
24
25/// Data representation of on-chain data such as Datums and Redeemers
26#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28pub enum PlutusData {
29    Constr(BigInt, Vec<PlutusData>),
30    Map(Vec<(PlutusData, PlutusData)>),
31    List(Vec<PlutusData>),
32    Integer(BigInt),
33    Bytes(Vec<u8>),
34}
35
36#[derive(Clone, Debug)]
37pub enum PlutusType {
38    Constr,
39    Map,
40    List,
41    Integer,
42    Bytes,
43}
44
45pub trait IsPlutusData {
46    fn to_plutus_data(&self) -> PlutusData;
47
48    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError>
49    where
50        Self: Sized;
51}
52
53// TODO(chfanghr): improve error reporting
54#[derive(Clone, Debug, thiserror::Error)]
55pub enum PlutusDataError {
56    #[error("Expected a PlutusData type {wanted:?}, but got {got:?}")]
57    UnexpectedPlutusType { got: PlutusType, wanted: PlutusType },
58    #[error("Expected a PlutusData type as {wanted:?}, but got {got:?}")]
59    UnexpectedPlutusInvariant { got: String, wanted: String },
60    #[error("Expected a Plutus List with {wanted:?} elements, but got {got:?} elements")]
61    UnexpectedListLength { got: usize, wanted: usize },
62    #[error("Some internal error happened: {0}")]
63    InternalError(String),
64}
65
66impl From<&PlutusData> for PlutusType {
67    fn from(plutus_data: &PlutusData) -> Self {
68        match plutus_data {
69            PlutusData::Constr(_, _) => PlutusType::Constr,
70            PlutusData::Map(_) => PlutusType::Map,
71            PlutusData::List(_) => PlutusType::List,
72            PlutusData::Integer(_) => PlutusType::Integer,
73            PlutusData::Bytes(_) => PlutusType::Bytes,
74        }
75    }
76}
77
78impl PlutusData {
79    pub fn constr(tag: u32, fields: Vec<PlutusData>) -> Self {
80        PlutusData::Constr(BigInt::from(tag), fields)
81    }
82
83    pub fn map(fields: Vec<(PlutusData, PlutusData)>) -> Self {
84        PlutusData::Map(fields)
85    }
86
87    pub fn list(fields: Vec<PlutusData>) -> Self {
88        PlutusData::List(fields)
89    }
90
91    pub fn integer(value: u32) -> Self {
92        PlutusData::Integer(BigInt::from(value))
93    }
94
95    pub fn bytes(value: Vec<u8>) -> Self {
96        PlutusData::Bytes(value)
97    }
98}
99
100impl IsPlutusData for PlutusData {
101    fn to_plutus_data(&self) -> PlutusData {
102        self.clone()
103    }
104
105    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
106        Ok(plutus_data.clone())
107    }
108}
109
110impl TryFromCSL<csl::PlutusData> for PlutusData {
111    fn try_from_csl(value: &csl::PlutusData) -> Result<Self, TryFromCSLError> {
112        Ok(match value.kind() {
113            csl::PlutusDataKind::ConstrPlutusData => {
114                let constr_data = value.as_constr_plutus_data().unwrap();
115                let tag = BigInt::from_csl(&constr_data.alternative());
116                let args = constr_data.data().try_to_pla()?;
117                PlutusData::Constr(tag, args)
118            }
119            csl::PlutusDataKind::Map => PlutusData::Map(value.as_map().unwrap().try_to_pla()?),
120            csl::PlutusDataKind::List => PlutusData::List(value.as_list().unwrap().try_to_pla()?),
121            csl::PlutusDataKind::Integer => {
122                PlutusData::Integer(value.as_integer().unwrap().try_to_pla()?)
123            }
124            csl::PlutusDataKind::Bytes => PlutusData::Bytes(value.as_bytes().unwrap()),
125        })
126    }
127}
128
129#[cfg(feature = "lbf")]
130impl Json for PlutusData {
131    fn to_json(&self) -> serde_json::Value {
132        match self {
133            PlutusData::Constr(index, fields) => json_constructor(
134                "Constr",
135                vec![json_object(vec![
136                    ("index".to_string(), index.to_json()),
137                    ("fields".to_string(), fields.to_json()),
138                ])],
139            ),
140            PlutusData::Map(map) => json_constructor("Map", vec![map.to_json()]),
141            PlutusData::List(list) => json_constructor("List", vec![list.to_json()]),
142            PlutusData::Integer(int) => json_constructor("Integer", vec![int.to_json()]),
143            PlutusData::Bytes(bytes) => {
144                json_constructor("Bytes", vec![String::to_json(&HEXLOWER.encode(bytes))])
145            }
146        }
147    }
148
149    fn from_json(value: &serde_json::Value) -> Result<PlutusData, Error> {
150        case_json_constructor(
151            "PlutusV1.PlutusData",
152            vec![
153                (
154                    "Constr",
155                    Box::new(|ctor_fields| match &ctor_fields[..] {
156                        [val] => case_json_object(
157                            |obj| {
158                                let index = obj.get("index").ok_or(Error::UnexpectedFieldName {
159                                    wanted: "index".to_owned(),
160                                    got: obj.keys().cloned().collect(),
161                                    parser: "PlutusV1.PlutusData".to_owned(),
162                                })?;
163
164                                let fields =
165                                    obj.get("fields").ok_or(Error::UnexpectedFieldName {
166                                        wanted: "fields".to_owned(),
167                                        got: obj.keys().cloned().collect(),
168                                        parser: "PlutusV1.PlutusData".to_owned(),
169                                    })?;
170                                Ok(PlutusData::Constr(
171                                    BigInt::from_json(index)?,
172                                    <Vec<PlutusData>>::from_json(fields)?,
173                                ))
174                            },
175                            val,
176                        ),
177                        _ => Err(Error::UnexpectedArrayLength {
178                            wanted: 1,
179                            got: ctor_fields.len(),
180                            parser: "PlutusV1.PlutusData".to_owned(),
181                        }),
182                    }),
183                ),
184                (
185                    "Map",
186                    Box::new(|ctor_fields| match &ctor_fields[..] {
187                        [val] => Ok(PlutusData::Map(Json::from_json(val)?)),
188                        _ => Err(Error::UnexpectedArrayLength {
189                            wanted: 1,
190                            got: ctor_fields.len(),
191                            parser: "PlutusV1.PlutusData".to_owned(),
192                        }),
193                    }),
194                ),
195                (
196                    "List",
197                    Box::new(|ctor_fields| match &ctor_fields[..] {
198                        [val] => Ok(PlutusData::List(Json::from_json(val)?)),
199                        _ => Err(Error::UnexpectedArrayLength {
200                            wanted: 1,
201                            got: ctor_fields.len(),
202                            parser: "PlutusV1.PlutusData".to_owned(),
203                        }),
204                    }),
205                ),
206                (
207                    "Integer",
208                    Box::new(|ctor_fields| match &ctor_fields[..] {
209                        [val] => Ok(PlutusData::Integer(Json::from_json(val)?)),
210                        _ => Err(Error::UnexpectedArrayLength {
211                            wanted: 1,
212                            got: ctor_fields.len(),
213                            parser: "PlutusV1.PlutusData".to_owned(),
214                        }),
215                    }),
216                ),
217                (
218                    "Bytes",
219                    Box::new(|ctor_fields| match &ctor_fields[..] {
220                        [val] => {
221                            let bytes = String::from_json(val).and_then(|str| {
222                                HEXLOWER.decode(&str.into_bytes()).map_err(|_| {
223                                    Error::UnexpectedJsonInvariant {
224                                        wanted: "base16 string".to_owned(),
225                                        got: "unexpected string".to_owned(),
226                                        parser: "Plutus.V1.Bytes".to_owned(),
227                                    }
228                                })
229                            })?;
230                            Ok(PlutusData::Bytes(bytes))
231                        }
232                        _ => Err(Error::UnexpectedArrayLength {
233                            wanted: 1,
234                            got: ctor_fields.len(),
235                            parser: "PlutusV1.PlutusData".to_owned(),
236                        }),
237                    }),
238                ),
239            ],
240            value,
241        )
242    }
243}
244
245// MARK: Orphan IsPlutusData Instances
246
247impl IsPlutusData for BigInt {
248    fn to_plutus_data(&self) -> PlutusData {
249        PlutusData::Integer(self.clone())
250    }
251
252    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
253        match plutus_data {
254            PlutusData::Integer(int) => Ok(int.clone()),
255            _ => Err(PlutusDataError::UnexpectedPlutusType {
256                wanted: PlutusType::Integer,
257                got: PlutusType::from(plutus_data),
258            }),
259        }
260    }
261}
262
263impl IsPlutusData for Vec<u8> {
264    fn to_plutus_data(&self) -> PlutusData {
265        PlutusData::Bytes(self.clone())
266    }
267
268    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
269        match plutus_data {
270            PlutusData::Bytes(bytes) => Ok(bytes.clone()),
271            _ => Err(PlutusDataError::UnexpectedPlutusType {
272                wanted: PlutusType::Bytes,
273                got: PlutusType::from(plutus_data),
274            }),
275        }
276    }
277}
278
279const BOOL_FALSE_TAG: u32 = 0;
280const BOOL_TRUE_TAG: u32 = 1;
281
282impl IsPlutusData for bool {
283    fn to_plutus_data(&self) -> PlutusData {
284        if *self {
285            PlutusData::Constr(BOOL_TRUE_TAG.into(), vec![])
286        } else {
287            PlutusData::Constr(BOOL_FALSE_TAG.into(), vec![])
288        }
289    }
290
291    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
292        let (tag, fields) = parse_constr(plutus_data)?;
293        let [] = parse_fixed_len_constr_fields::<0>(fields)?;
294        match tag {
295            BOOL_TRUE_TAG => Ok(true),
296            BOOL_FALSE_TAG => Ok(false),
297            _ => Err(PlutusDataError::UnexpectedPlutusInvariant {
298                wanted: format!("Constr with tag {BOOL_TRUE_TAG} or {BOOL_FALSE_TAG}"),
299                got: tag.to_string(),
300            }),
301        }
302    }
303}
304
305impl IsPlutusData for String {
306    fn to_plutus_data(&self) -> PlutusData {
307        PlutusData::Bytes(self.as_bytes().into())
308    }
309
310    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
311        match plutus_data {
312            PlutusData::Bytes(bytes) => String::from_utf8(bytes.clone()).map_err(|err| {
313                PlutusDataError::InternalError(format!(
314                    "Couldn't convert Plutus bytes to String: {:?}",
315                    err
316                ))
317            }),
318            _ => Err(PlutusDataError::UnexpectedPlutusType {
319                wanted: PlutusType::Bytes,
320                got: PlutusType::from(plutus_data),
321            }),
322        }
323    }
324}
325
326impl IsPlutusData for char {
327    fn to_plutus_data(&self) -> PlutusData {
328        String::from(*self).to_plutus_data()
329    }
330
331    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
332        String::from_plutus_data(plutus_data).and_then(|str| {
333            let mut chars = str.chars();
334            let ch = chars.next();
335            let rest = chars.next();
336            match (ch, rest) {
337                (Some(ch), None) => Ok(ch),
338                _ => Err(PlutusDataError::UnexpectedPlutusInvariant {
339                    got: "string".to_owned(),
340                    wanted: "char".to_owned(),
341                }),
342            }
343        })
344    }
345}
346
347const OPTION_SOME_TAG: u32 = 0;
348const OPTION_NONE_TAG: u32 = 1;
349
350impl<T> IsPlutusData for Option<T>
351where
352    T: IsPlutusData,
353{
354    fn to_plutus_data(&self) -> PlutusData {
355        match self {
356            Some(val) => PlutusData::Constr(OPTION_SOME_TAG.into(), vec![val.to_plutus_data()]),
357            None => PlutusData::Constr(OPTION_NONE_TAG.into(), vec![]),
358        }
359    }
360
361    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
362        let (tag, fields) = parse_constr(plutus_data)?;
363
364        match tag {
365            OPTION_SOME_TAG => {
366                let [data] = parse_fixed_len_constr_fields::<1>(fields)?;
367                Ok(Some(T::from_plutus_data(data)?))
368            }
369            OPTION_NONE_TAG => {
370                let [] = parse_fixed_len_constr_fields::<0>(fields)?;
371                Ok(None)
372            }
373            _ => Err(PlutusDataError::UnexpectedPlutusInvariant {
374                wanted: format!("Constr with tag {OPTION_SOME_TAG} or {OPTION_NONE_TAG}"),
375                got: tag.to_string(),
376            }),
377        }
378    }
379}
380
381const RESULT_ERR_TAG: u32 = 0;
382const RESULT_OK_TAG: u32 = 1;
383
384impl<T, E> IsPlutusData for Result<T, E>
385where
386    T: IsPlutusData,
387    E: IsPlutusData,
388{
389    fn to_plutus_data(&self) -> PlutusData {
390        match self {
391            Err(err) => PlutusData::Constr(RESULT_ERR_TAG.into(), vec![err.to_plutus_data()]),
392            Ok(val) => PlutusData::Constr(RESULT_OK_TAG.into(), vec![val.to_plutus_data()]),
393        }
394    }
395
396    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
397        let (tag, fields) = parse_constr(plutus_data)?;
398        let [field] = parse_fixed_len_constr_fields::<1>(fields)?;
399
400        match tag {
401            RESULT_ERR_TAG => Ok(Err(E::from_plutus_data(field)?)),
402            RESULT_OK_TAG => Ok(Ok(T::from_plutus_data(field)?)),
403            _ => Err(PlutusDataError::UnexpectedPlutusInvariant {
404                wanted: format!("Constr with tag {RESULT_ERR_TAG} or {RESULT_OK_TAG}"),
405                got: tag.to_string(),
406            }),
407        }
408    }
409}
410
411impl<T> IsPlutusData for Vec<T>
412where
413    T: IsPlutusData,
414{
415    fn to_plutus_data(&self) -> PlutusData {
416        let values = self
417            .iter()
418            .map(|val| val.to_plutus_data())
419            .collect::<Vec<PlutusData>>();
420
421        PlutusData::List(values)
422    }
423
424    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
425        let list = parse_list(plutus_data)?;
426        list.iter().map(T::from_plutus_data).collect()
427    }
428}
429
430impl<T> IsPlutusData for BTreeSet<T>
431where
432    T: IsPlutusData + Eq + Ord,
433{
434    fn to_plutus_data(&self) -> PlutusData {
435        let set = self
436            .iter()
437            .map(|val| val.to_plutus_data())
438            .collect::<Vec<PlutusData>>();
439
440        PlutusData::List(set)
441    }
442
443    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
444        match plutus_data {
445            PlutusData::List(vec) => vec
446                .iter()
447                .map(|val| T::from_plutus_data(val))
448                .collect::<Result<Self, PlutusDataError>>(),
449            _ => Err(PlutusDataError::UnexpectedPlutusType {
450                wanted: PlutusType::List,
451                got: PlutusType::from(plutus_data),
452            }),
453        }
454    }
455}
456
457impl<K, V> IsPlutusData for BTreeMap<K, V>
458where
459    K: IsPlutusData + Eq + Ord,
460    V: IsPlutusData,
461{
462    fn to_plutus_data(&self) -> PlutusData {
463        let assoc_map = self
464            .iter()
465            .map(|(key, val)| (key.to_plutus_data(), val.to_plutus_data()))
466            .collect::<Vec<(PlutusData, PlutusData)>>();
467
468        PlutusData::Map(assoc_map)
469    }
470
471    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
472        match plutus_data {
473            PlutusData::Map(dict) => dict
474                .iter()
475                .map(|(key, val)| Ok((K::from_plutus_data(key)?, V::from_plutus_data(val)?)))
476                .collect::<Result<Self, PlutusDataError>>(),
477            _ => Err(PlutusDataError::UnexpectedPlutusType {
478                wanted: PlutusType::Map,
479                got: PlutusType::from(plutus_data),
480            }),
481        }
482    }
483}
484
485const UNIT_TAG: u32 = 0;
486
487impl IsPlutusData for () {
488    fn to_plutus_data(&self) -> PlutusData {
489        PlutusData::Constr(UNIT_TAG.into(), vec![])
490    }
491
492    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
493        let fields = parse_constr_with_tag(plutus_data, UNIT_TAG)?;
494        let [] = parse_fixed_len_constr_fields::<0>(fields)?;
495        Ok(())
496    }
497}
498
499const PAIR_TAG: u32 = 0;
500
501impl<A, B> IsPlutusData for (A, B)
502where
503    A: IsPlutusData,
504    B: IsPlutusData,
505{
506    fn to_plutus_data(&self) -> PlutusData {
507        PlutusData::Constr(
508            BigInt::from(PAIR_TAG),
509            vec![self.0.to_plutus_data(), self.1.to_plutus_data()],
510        )
511    }
512
513    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
514        let fields = parse_constr_with_tag(plutus_data, PAIR_TAG)?;
515        let [a, b] = parse_fixed_len_constr_fields::<2>(fields)?;
516        Ok((A::from_plutus_data(a)?, B::from_plutus_data(b)?))
517    }
518}
519
520// MARK: Orphan TryFromCSL instances
521
522impl TryFromCSL<csl::PlutusList> for Vec<PlutusData> {
523    fn try_from_csl(value: &csl::PlutusList) -> Result<Self, TryFromCSLError> {
524        (0..value.len())
525            .map(|idx| value.get(idx).try_to_pla())
526            .collect()
527    }
528}
529
530impl TryFromCSL<csl::PlutusMap> for Vec<(PlutusData, PlutusData)> {
531    fn try_from_csl(c_map: &csl::PlutusMap) -> Result<Self, TryFromCSLError> {
532        let keys = c_map.keys();
533        (0..keys.len()).try_fold(Vec::new(), |mut vector, idx| {
534            let key = keys.get(idx);
535            let values = c_map.get(&key).unwrap();
536
537            for value_idx in 0..values.len() {
538                vector.push((
539                    key.clone().try_to_pla()?,
540                    values.get(value_idx).unwrap().try_to_pla()?,
541                ))
542            }
543
544            Ok(vector)
545        })
546    }
547}
548
549impl TryFromPLA<PlutusData> for csl::PlutusData {
550    fn try_from_pla(val: &PlutusData) -> Result<Self, TryFromPLAError> {
551        match val {
552            PlutusData::Constr(tag, args) => Ok(csl::PlutusData::new_constr_plutus_data(
553                &csl::ConstrPlutusData::new(&tag.try_to_csl()?, &args.try_to_csl()?),
554            )),
555            PlutusData::Map(l) => Ok(csl::PlutusData::new_map(&l.try_to_csl()?)),
556            PlutusData::List(l) => Ok(csl::PlutusData::new_list(&l.try_to_csl()?)),
557            PlutusData::Integer(i) => Ok(csl::PlutusData::new_integer(&i.try_to_csl()?)),
558            PlutusData::Bytes(b) => Ok(csl::PlutusData::new_bytes(b.to_owned())),
559        }
560    }
561}
562
563impl TryFromPLA<Vec<PlutusData>> for csl::PlutusList {
564    fn try_from_pla(val: &Vec<PlutusData>) -> Result<Self, TryFromPLAError> {
565        val.iter()
566            // traverse
567            .map(|x| x.try_to_csl())
568            .collect::<Result<Vec<csl::PlutusData>, TryFromPLAError>>()
569            .map(|x| x.into())
570    }
571}
572
573impl TryFromPLA<Vec<(PlutusData, PlutusData)>> for csl::PlutusMap {
574    fn try_from_pla(val: &Vec<(PlutusData, PlutusData)>) -> Result<Self, TryFromPLAError> {
575        val.iter()
576            .try_fold(csl::PlutusMap::new(), |mut acc, (k, v)| {
577                let mut values = match acc.get(&k.try_to_csl()?) {
578                    Some(existing_values) => existing_values,
579                    None => csl::PlutusMapValues::new(),
580                };
581                values.add(&v.try_to_csl()?);
582                acc.insert(&k.try_to_csl()?, &values);
583                Ok(acc)
584            })
585    }
586}
587
588// MARK: Aux functions
589
590/// Deserialise a Plutus data using parsers for each variant
591pub fn case_plutus_data<'a, T>(
592    ctor_case: impl FnOnce(&'a BigInt) -> Box<dyn 'a + FnOnce(&'a Vec<PlutusData>) -> T>,
593    list_case: impl FnOnce(&'a Vec<PlutusData>) -> T,
594    int_case: impl FnOnce(&'a BigInt) -> T,
595    other_case: impl FnOnce(&'a PlutusData) -> T,
596    pd: &'a PlutusData,
597) -> T {
598    match pd {
599        PlutusData::Constr(tag, args) => ctor_case(&tag)(&args),
600        PlutusData::List(args) => list_case(&args),
601        PlutusData::Integer(i) => int_case(&i),
602        other => other_case(&other),
603    }
604}
605
606/// Given a vector of PlutusData, parse it as an array whose length is known at
607/// compile time.
608///
609/// This function is used by the derive macro.
610pub fn parse_fixed_len_constr_fields<const LEN: usize>(
611    v: &[PlutusData],
612) -> Result<&[PlutusData; LEN], PlutusDataError> {
613    v.try_into()
614        .map_err(|_| PlutusDataError::UnexpectedListLength {
615            got: v.len(),
616            wanted: LEN,
617        })
618}
619
620/// Given a PlutusData, parse it as PlutusData::Constr and its tag as u32. Return
621/// the u32 tag and fields.
622///
623/// This function is used by the derive macro.
624pub fn parse_constr(data: &PlutusData) -> Result<(u32, &Vec<PlutusData>), PlutusDataError> {
625    match data {
626        PlutusData::Constr(tag, fields) => u32::try_from(tag)
627            .map_err(|err| PlutusDataError::UnexpectedPlutusInvariant {
628                got: err.to_string(),
629                wanted: "Constr bigint tag within u32 range".into(),
630            })
631            .map(|tag| (tag, fields)),
632        _ => Err(PlutusDataError::UnexpectedPlutusType {
633            wanted: PlutusType::Constr,
634            got: PlutusType::from(data),
635        }),
636    }
637}
638
639/// Given a PlutusData, parse it as PlutusData::Constr and verify its tag.
640///
641/// This function is used by the derive macro.
642pub fn parse_constr_with_tag(
643    data: &PlutusData,
644    expected_tag: u32,
645) -> Result<&Vec<PlutusData>, PlutusDataError> {
646    let (tag, fields) = parse_constr(data)?;
647
648    if tag != expected_tag {
649        Err(PlutusDataError::UnexpectedPlutusInvariant {
650            got: tag.to_string(),
651            wanted: format!("Constr with tag {}", expected_tag),
652        })
653    } else {
654        Ok(fields)
655    }
656}
657
658/// Given a PlutusData, parse it as PlutusData::List. Return the plutus data list.
659///
660/// This function is used by the derive macro.
661pub fn parse_list(data: &PlutusData) -> Result<&Vec<PlutusData>, PlutusDataError> {
662    match data {
663        PlutusData::List(list_of_plutus_data) => Ok(list_of_plutus_data),
664        _ => Err(PlutusDataError::UnexpectedPlutusType {
665            got: PlutusType::from(data),
666            wanted: PlutusType::List,
667        }),
668    }
669}