daml_lf/convert/
type_payload.rs

1use std::borrow::Cow;
2use std::convert::{TryFrom, TryInto};
3
4use crate::convert::field_payload::DamlFieldPayload;
5use crate::convert::interned::{InternableDottedName, InternableString, PackageInternedResolver};
6use crate::convert::typevar_payload::DamlTypeVarWithKindPayload;
7use crate::convert::util::Required;
8use crate::convert::wrapper::PayloadElementWrapper;
9use crate::error::{DamlLfConvertError, DamlLfConvertResult};
10use crate::lf_protobuf::com::daml::daml_lf_1::r#type::{Con, Forall, Struct, Sum, Syn, Var};
11use crate::lf_protobuf::com::daml::daml_lf_1::{package_ref, PrimType, TypeSynName};
12use crate::lf_protobuf::com::daml::daml_lf_1::{ModuleRef, PackageRef, Type, TypeConName};
13
14///
15pub type DamlTypeWrapper<'a> = PayloadElementWrapper<'a, &'a DamlTypePayload<'a>>;
16
17#[derive(Debug)]
18pub enum DamlTypePayload<'a> {
19    ContractId(Option<Box<DamlTypePayload<'a>>>),
20    Int64,
21    Numeric(Vec<DamlTypePayload<'a>>),
22    Text,
23    Timestamp,
24    Party,
25    Bool,
26    Unit,
27    Date,
28    List(Vec<DamlTypePayload<'a>>),
29    Update,
30    Scenario,
31    TextMap(Vec<DamlTypePayload<'a>>),
32    GenMap(Vec<DamlTypePayload<'a>>),
33    Optional(Vec<DamlTypePayload<'a>>),
34    TyCon(DamlTyConPayload<'a>),
35    Var(DamlVarPayload<'a>),
36    Arrow,
37    Any,
38    TypeRep,
39    Bignumeric,
40    RoundingMode,
41    AnyException,
42    Nat(u8),
43    Forall(DamlForallPayload<'a>),
44    Struct(DamlStructPayload<'a>),
45    Syn(DamlSynPayload<'a>),
46    Interned(i32),
47}
48
49impl<'a> DamlTypePayload<'a> {
50    pub fn name_for_error(&self) -> &'static str {
51        match self {
52            DamlTypePayload::ContractId(_) => "ContractId",
53            DamlTypePayload::Int64 => "Int64",
54            DamlTypePayload::Numeric(_) => "Numeric",
55            DamlTypePayload::Text => "Text",
56            DamlTypePayload::Timestamp => "Timestamp",
57            DamlTypePayload::Party => "Party",
58            DamlTypePayload::Bool => "Bool",
59            DamlTypePayload::Unit => "Unit",
60            DamlTypePayload::Date => "Date",
61            DamlTypePayload::List(_) => "List",
62            DamlTypePayload::Update => "Update",
63            DamlTypePayload::Scenario => "Scenario",
64            DamlTypePayload::TextMap(_) => "TextMap",
65            DamlTypePayload::GenMap(_) => "GenMap",
66            DamlTypePayload::Optional(_) => "Optional",
67            DamlTypePayload::TyCon(_) => "TyCon",
68            DamlTypePayload::Var(_) => "Var",
69            DamlTypePayload::Arrow => "Arrow",
70            DamlTypePayload::Any => "Any",
71            DamlTypePayload::TypeRep => "TypeRep",
72            DamlTypePayload::Bignumeric => "Bignumeric",
73            DamlTypePayload::RoundingMode => "RoundingMode",
74            DamlTypePayload::AnyException => "AnyException",
75            DamlTypePayload::Nat(_) => "Nat",
76            DamlTypePayload::Forall(_) => "Forall",
77            DamlTypePayload::Struct(_) => "Struct",
78            DamlTypePayload::Syn(_) => "Syn",
79            DamlTypePayload::Interned(_) => "Interned",
80        }
81    }
82}
83
84/// The nat value to use for legacy Decimal types.
85pub const LEGACY_DECIMAL_NAT: u8 = 10;
86
87impl<'a> TryFrom<&'a Type> for DamlTypePayload<'a> {
88    type Error = DamlLfConvertError;
89
90    fn try_from(ty: &'a Type) -> DamlLfConvertResult<Self> {
91        match ty.sum.as_ref().req()? {
92            Sum::Prim(prim) => match PrimType::from_i32(prim.prim).req()? {
93                PrimType::Unit => Ok(DamlTypePayload::Unit),
94                PrimType::Bool => Ok(DamlTypePayload::Bool),
95                PrimType::Int64 => Ok(DamlTypePayload::Int64),
96                PrimType::Numeric => Ok(DamlTypePayload::Numeric(try_from_type_args(&prim.args)?)),
97                PrimType::Decimal => Ok(DamlTypePayload::Numeric(vec![DamlTypePayload::Nat(LEGACY_DECIMAL_NAT)])),
98                PrimType::Text => Ok(DamlTypePayload::Text),
99                PrimType::Timestamp => Ok(DamlTypePayload::Timestamp),
100                PrimType::Party => Ok(DamlTypePayload::Party),
101                PrimType::List => Ok(DamlTypePayload::List(try_from_type_args(&prim.args)?)),
102                PrimType::Update => Ok(DamlTypePayload::Update),
103                PrimType::Scenario => Ok(DamlTypePayload::Scenario),
104                PrimType::Date => Ok(DamlTypePayload::Date),
105                PrimType::ContractId => match prim.args.as_slice() {
106                    [ty] => Ok(DamlTypePayload::ContractId(Some(Box::new(DamlTypePayload::try_from(ty)?)))),
107                    args if !args.is_empty() => Err(DamlLfConvertError::UnexpectedContractIdTypeArguments),
108                    _ => Ok(DamlTypePayload::ContractId(None)),
109                },
110                PrimType::Optional => Ok(DamlTypePayload::Optional(try_from_type_args(&prim.args)?)),
111                PrimType::Arrow => Ok(DamlTypePayload::Arrow),
112                PrimType::Textmap => Ok(DamlTypePayload::TextMap(try_from_type_args(&prim.args)?)),
113                PrimType::Genmap => Ok(DamlTypePayload::GenMap(try_from_type_args(&prim.args)?)),
114                PrimType::Any => Ok(DamlTypePayload::Any),
115                PrimType::TypeRep => Ok(DamlTypePayload::TypeRep),
116                PrimType::Bignumeric => Ok(DamlTypePayload::Bignumeric),
117                PrimType::RoundingMode => Ok(DamlTypePayload::RoundingMode),
118                PrimType::AnyException => Ok(DamlTypePayload::AnyException),
119            },
120            Sum::Con(con) => Ok(DamlTypePayload::TyCon(DamlTyConPayload::try_from(con)?)),
121            Sum::Var(var) => Ok(DamlTypePayload::Var(DamlVarPayload::try_from(var)?)),
122            Sum::Nat(n) =>
123                if *n >= 0 && *n <= 37 {
124                    #[allow(clippy::cast_possible_truncation)]
125                    Ok(DamlTypePayload::Nat(*n as u8))
126                } else {
127                    Err(DamlLfConvertError::NatOutOfRange(*n))
128                },
129            Sum::Forall(forall) => Ok(DamlTypePayload::Forall(DamlForallPayload::try_from(forall.as_ref())?)),
130            Sum::Struct(tuple) => Ok(DamlTypePayload::Struct(DamlStructPayload::try_from(tuple)?)),
131            Sum::Syn(syn) => Ok(DamlTypePayload::Syn(DamlSynPayload::try_from(syn)?)),
132            Sum::Interned(i) => Ok(DamlTypePayload::Interned(*i)),
133        }
134    }
135}
136
137pub type DamlSynWrapper<'a> = PayloadElementWrapper<'a, &'a DamlSynPayload<'a>>;
138
139#[derive(Debug)]
140pub struct DamlSynPayload<'a> {
141    pub tysyn: DamlTypeSynNamePayload<'a>,
142    pub args: Vec<DamlTypePayload<'a>>,
143}
144
145impl<'a> DamlSynPayload<'a> {
146    pub fn new(tysyn: DamlTypeSynNamePayload<'a>, args: Vec<DamlTypePayload<'a>>) -> Self {
147        Self {
148            tysyn,
149            args,
150        }
151    }
152}
153
154impl<'a> TryFrom<&'a Syn> for DamlSynPayload<'a> {
155    type Error = DamlLfConvertError;
156
157    fn try_from(syn: &'a Syn) -> DamlLfConvertResult<Self> {
158        let tysyn = DamlTypeSynNamePayload::try_from(syn.tysyn.as_ref().req()?)?;
159        let args = try_from_type_args(&syn.args)?;
160        Ok(DamlSynPayload::new(tysyn, args))
161    }
162}
163
164pub type DamlTypeSynNameWrapper<'a> = PayloadElementWrapper<'a, &'a DamlTypeSynNamePayload<'a>>;
165
166#[derive(Debug)]
167pub struct DamlTypeSynNamePayload<'a> {
168    pub package_ref: DamlPackageRefPayload<'a>,
169    pub module_path: InternableDottedName<'a>,
170    pub data_name: InternableDottedName<'a>,
171}
172
173impl<'a> DamlTypeSynNamePayload<'a> {
174    pub fn new(
175        package_ref: DamlPackageRefPayload<'a>,
176        module_path: InternableDottedName<'a>,
177        data_name: InternableDottedName<'a>,
178    ) -> Self {
179        Self {
180            package_ref,
181            module_path,
182            data_name,
183        }
184    }
185}
186
187impl<'a> TryFrom<&'a TypeSynName> for DamlTypeSynNamePayload<'a> {
188    type Error = DamlLfConvertError;
189
190    fn try_from(tysyn: &'a TypeSynName) -> DamlLfConvertResult<Self> {
191        match tysyn {
192            TypeSynName {
193                module:
194                    Some(ModuleRef {
195                        package_ref: Some(package_ref),
196                        module_name: Some(module_name),
197                    }),
198                name: Some(data_name),
199            } => Ok(Self::new(
200                package_ref.try_into()?,
201                InternableDottedName::from(module_name),
202                InternableDottedName::from(data_name),
203            )),
204            _ => Err(DamlLfConvertError::MissingRequiredField),
205        }
206    }
207}
208
209///
210pub type DamlStructWrapper<'a> = PayloadElementWrapper<'a, &'a DamlStructPayload<'a>>;
211
212#[derive(Debug)]
213pub struct DamlStructPayload<'a> {
214    pub fields: Vec<DamlFieldPayload<'a>>,
215}
216
217impl<'a> DamlStructPayload<'a> {
218    pub fn new(fields: Vec<DamlFieldPayload<'a>>) -> Self {
219        Self {
220            fields,
221        }
222    }
223}
224
225impl<'a> TryFrom<&'a Struct> for DamlStructPayload<'a> {
226    type Error = DamlLfConvertError;
227
228    fn try_from(tuple: &'a Struct) -> DamlLfConvertResult<Self> {
229        let fields = tuple.fields.iter().map(DamlFieldPayload::try_from).collect::<DamlLfConvertResult<Vec<_>>>()?;
230        Ok(DamlStructPayload::new(fields))
231    }
232}
233
234///
235pub type DamlForallWrapper<'a> = PayloadElementWrapper<'a, &'a DamlForallPayload<'a>>;
236
237#[derive(Debug)]
238pub struct DamlForallPayload<'a> {
239    pub vars: Vec<DamlTypeVarWithKindPayload<'a>>,
240    pub body: Box<DamlTypePayload<'a>>,
241}
242
243impl<'a> DamlForallPayload<'a> {
244    pub fn new(vars: Vec<DamlTypeVarWithKindPayload<'a>>, body: Box<DamlTypePayload<'a>>) -> Self {
245        Self {
246            vars,
247            body,
248        }
249    }
250}
251
252impl<'a> TryFrom<&'a Forall> for DamlForallPayload<'a> {
253    type Error = DamlLfConvertError;
254
255    fn try_from(forall: &'a Forall) -> DamlLfConvertResult<Self> {
256        let vars =
257            forall.vars.iter().map(DamlTypeVarWithKindPayload::try_from).collect::<DamlLfConvertResult<Vec<_>>>()?;
258        let body = DamlTypePayload::try_from(forall.body.as_ref().req()?.as_ref())?;
259        Ok(DamlForallPayload::new(vars, Box::new(body)))
260    }
261}
262
263///
264pub type DamlTyConWrapper<'a> = PayloadElementWrapper<'a, &'a DamlTyConPayload<'a>>;
265
266#[derive(Debug)]
267pub struct DamlTyConPayload<'a> {
268    pub package_ref: DamlPackageRefPayload<'a>,
269    pub module_path: InternableDottedName<'a>,
270    pub data_name: InternableDottedName<'a>,
271    pub type_arguments: Vec<DamlTypePayload<'a>>,
272}
273
274impl<'a> DamlTyConPayload<'a> {
275    pub fn new(
276        package_ref: DamlPackageRefPayload<'a>,
277        module_path: InternableDottedName<'a>,
278        data_name: InternableDottedName<'a>,
279        type_arguments: Vec<DamlTypePayload<'a>>,
280    ) -> Self {
281        Self {
282            package_ref,
283            module_path,
284            data_name,
285            type_arguments,
286        }
287    }
288}
289
290impl<'a> TryFrom<&'a Con> for DamlTyConPayload<'a> {
291    type Error = DamlLfConvertError;
292
293    fn try_from(con: &'a Con) -> DamlLfConvertResult<Self> {
294        match con {
295            Con {
296                tycon:
297                    Some(TypeConName {
298                        module:
299                            Some(ModuleRef {
300                                package_ref: Some(package_ref),
301                                module_name: Some(module_name),
302                            }),
303                        name: Some(data_name),
304                    }),
305                args,
306            } => Ok(Self::new(
307                package_ref.try_into()?,
308                InternableDottedName::from(module_name),
309                InternableDottedName::from(data_name),
310                try_from_type_args(args)?,
311            )),
312            _ => Err(DamlLfConvertError::MissingRequiredField),
313        }
314    }
315}
316
317pub type DamlTyConNameWrapper<'a> = PayloadElementWrapper<'a, &'a DamlTyConNamePayload<'a>>;
318
319#[derive(Debug)]
320pub struct DamlTyConNamePayload<'a> {
321    pub package_ref: DamlPackageRefPayload<'a>,
322    pub module_path: InternableDottedName<'a>,
323    pub data_name: InternableDottedName<'a>,
324}
325
326impl<'a> DamlTyConNamePayload<'a> {
327    pub fn new(
328        package_ref: DamlPackageRefPayload<'a>,
329        module_path: InternableDottedName<'a>,
330        data_name: InternableDottedName<'a>,
331    ) -> Self {
332        Self {
333            package_ref,
334            module_path,
335            data_name,
336        }
337    }
338}
339
340impl<'a> TryFrom<&'a TypeConName> for DamlTyConNamePayload<'a> {
341    type Error = DamlLfConvertError;
342
343    fn try_from(con: &'a TypeConName) -> DamlLfConvertResult<Self> {
344        match con {
345            TypeConName {
346                module:
347                    Some(ModuleRef {
348                        package_ref: Some(package_ref),
349                        module_name: Some(module_name),
350                    }),
351                name: Some(data_name),
352            } => Ok(Self::new(
353                package_ref.try_into()?,
354                InternableDottedName::from(module_name),
355                InternableDottedName::from(data_name),
356            )),
357            _ => Err(DamlLfConvertError::MissingRequiredField),
358        }
359    }
360}
361
362#[derive(Debug, PartialEq)]
363pub enum DamlPackageRefPayload<'a> {
364    This,
365    PackageId(&'a str),
366    InternedId(i32),
367}
368
369impl<'a> DamlPackageRefPayload<'a> {
370    pub fn resolve(&self, resolver: &'a impl PackageInternedResolver) -> DamlLfConvertResult<Cow<'a, str>> {
371        Ok(match self {
372            DamlPackageRefPayload::This => Cow::from(resolver.package_id()),
373            &DamlPackageRefPayload::PackageId(s) => Cow::from(s),
374            &DamlPackageRefPayload::InternedId(i) => resolver.resolve_string(i)?,
375        })
376    }
377}
378
379impl<'a> TryFrom<&'a PackageRef> for DamlPackageRefPayload<'a> {
380    type Error = DamlLfConvertError;
381
382    fn try_from(package_ref: &'a PackageRef) -> DamlLfConvertResult<Self> {
383        Ok(match package_ref.sum.as_ref().req()? {
384            package_ref::Sum::Self_(_) => DamlPackageRefPayload::This,
385            package_ref::Sum::PackageIdStr(s) => DamlPackageRefPayload::PackageId(s.as_str()),
386            &package_ref::Sum::PackageIdInternedStr(i) => DamlPackageRefPayload::InternedId(i),
387        })
388    }
389}
390
391///
392pub type DamlVarWrapper<'a> = PayloadElementWrapper<'a, &'a DamlVarPayload<'a>>;
393
394#[derive(Debug)]
395pub struct DamlVarPayload<'a> {
396    pub var: InternableString<'a>,
397    pub type_arguments: Vec<DamlTypePayload<'a>>,
398}
399
400impl<'a> DamlVarPayload<'a> {
401    pub fn new(var: InternableString<'a>, type_arguments: Vec<DamlTypePayload<'a>>) -> Self {
402        Self {
403            var,
404            type_arguments,
405        }
406    }
407}
408
409impl<'a> TryFrom<&'a Var> for DamlVarPayload<'a> {
410    type Error = DamlLfConvertError;
411
412    fn try_from(var: &'a Var) -> DamlLfConvertResult<Self> {
413        Ok(DamlVarPayload::new(InternableString::from(var.var.as_ref().req()?), try_from_type_args(&var.args)?))
414    }
415}
416
417fn try_from_type_args(args: &[Type]) -> DamlLfConvertResult<Vec<DamlTypePayload<'_>>> {
418    args.iter().map(DamlTypePayload::try_from).collect::<DamlLfConvertResult<Vec<_>>>()
419}