daml-lf 0.2.2

API for working with Daml-LF data
Documentation
use std::borrow::Cow;
use std::convert::{TryFrom, TryInto};

use crate::convert::field_payload::DamlFieldPayload;
use crate::convert::interned::{InternableDottedName, InternableString, PackageInternedResolver};
use crate::convert::typevar_payload::DamlTypeVarWithKindPayload;
use crate::convert::util::Required;
use crate::convert::wrapper::PayloadElementWrapper;
use crate::error::{DamlLfConvertError, DamlLfConvertResult};
use crate::lf_protobuf::com::daml::daml_lf_1::r#type::{Con, Forall, Struct, Sum, Syn, Var};
use crate::lf_protobuf::com::daml::daml_lf_1::{package_ref, PrimType, TypeSynName};
use crate::lf_protobuf::com::daml::daml_lf_1::{ModuleRef, PackageRef, Type, TypeConName};

///
pub type DamlTypeWrapper<'a> = PayloadElementWrapper<'a, &'a DamlTypePayload<'a>>;

#[derive(Debug)]
pub enum DamlTypePayload<'a> {
    ContractId(Option<Box<DamlTypePayload<'a>>>),
    Int64,
    Numeric(Vec<DamlTypePayload<'a>>),
    Text,
    Timestamp,
    Party,
    Bool,
    Unit,
    Date,
    List(Vec<DamlTypePayload<'a>>),
    Update,
    Scenario,
    TextMap(Vec<DamlTypePayload<'a>>),
    GenMap(Vec<DamlTypePayload<'a>>),
    Optional(Vec<DamlTypePayload<'a>>),
    TyCon(DamlTyConPayload<'a>),
    Var(DamlVarPayload<'a>),
    Arrow,
    Any,
    TypeRep,
    Bignumeric,
    RoundingMode,
    AnyException,
    Nat(u8),
    Forall(DamlForallPayload<'a>),
    Struct(DamlStructPayload<'a>),
    Syn(DamlSynPayload<'a>),
    Interned(i32),
}

impl<'a> DamlTypePayload<'a> {
    pub fn name_for_error(&self) -> &'static str {
        match self {
            DamlTypePayload::ContractId(_) => "ContractId",
            DamlTypePayload::Int64 => "Int64",
            DamlTypePayload::Numeric(_) => "Numeric",
            DamlTypePayload::Text => "Text",
            DamlTypePayload::Timestamp => "Timestamp",
            DamlTypePayload::Party => "Party",
            DamlTypePayload::Bool => "Bool",
            DamlTypePayload::Unit => "Unit",
            DamlTypePayload::Date => "Date",
            DamlTypePayload::List(_) => "List",
            DamlTypePayload::Update => "Update",
            DamlTypePayload::Scenario => "Scenario",
            DamlTypePayload::TextMap(_) => "TextMap",
            DamlTypePayload::GenMap(_) => "GenMap",
            DamlTypePayload::Optional(_) => "Optional",
            DamlTypePayload::TyCon(_) => "TyCon",
            DamlTypePayload::Var(_) => "Var",
            DamlTypePayload::Arrow => "Arrow",
            DamlTypePayload::Any => "Any",
            DamlTypePayload::TypeRep => "TypeRep",
            DamlTypePayload::Bignumeric => "Bignumeric",
            DamlTypePayload::RoundingMode => "RoundingMode",
            DamlTypePayload::AnyException => "AnyException",
            DamlTypePayload::Nat(_) => "Nat",
            DamlTypePayload::Forall(_) => "Forall",
            DamlTypePayload::Struct(_) => "Struct",
            DamlTypePayload::Syn(_) => "Syn",
            DamlTypePayload::Interned(_) => "Interned",
        }
    }
}

/// The nat value to use for legacy Decimal types.
pub const LEGACY_DECIMAL_NAT: u8 = 10;

impl<'a> TryFrom<&'a Type> for DamlTypePayload<'a> {
    type Error = DamlLfConvertError;

    fn try_from(ty: &'a Type) -> DamlLfConvertResult<Self> {
        match ty.sum.as_ref().req()? {
            Sum::Prim(prim) => match PrimType::from_i32(prim.prim).req()? {
                PrimType::Unit => Ok(DamlTypePayload::Unit),
                PrimType::Bool => Ok(DamlTypePayload::Bool),
                PrimType::Int64 => Ok(DamlTypePayload::Int64),
                PrimType::Numeric => Ok(DamlTypePayload::Numeric(try_from_type_args(&prim.args)?)),
                PrimType::Decimal => Ok(DamlTypePayload::Numeric(vec![DamlTypePayload::Nat(LEGACY_DECIMAL_NAT)])),
                PrimType::Text => Ok(DamlTypePayload::Text),
                PrimType::Timestamp => Ok(DamlTypePayload::Timestamp),
                PrimType::Party => Ok(DamlTypePayload::Party),
                PrimType::List => Ok(DamlTypePayload::List(try_from_type_args(&prim.args)?)),
                PrimType::Update => Ok(DamlTypePayload::Update),
                PrimType::Scenario => Ok(DamlTypePayload::Scenario),
                PrimType::Date => Ok(DamlTypePayload::Date),
                PrimType::ContractId => match prim.args.as_slice() {
                    [ty] => Ok(DamlTypePayload::ContractId(Some(Box::new(DamlTypePayload::try_from(ty)?)))),
                    args if !args.is_empty() => Err(DamlLfConvertError::UnexpectedContractIdTypeArguments),
                    _ => Ok(DamlTypePayload::ContractId(None)),
                },
                PrimType::Optional => Ok(DamlTypePayload::Optional(try_from_type_args(&prim.args)?)),
                PrimType::Arrow => Ok(DamlTypePayload::Arrow),
                PrimType::Textmap => Ok(DamlTypePayload::TextMap(try_from_type_args(&prim.args)?)),
                PrimType::Genmap => Ok(DamlTypePayload::GenMap(try_from_type_args(&prim.args)?)),
                PrimType::Any => Ok(DamlTypePayload::Any),
                PrimType::TypeRep => Ok(DamlTypePayload::TypeRep),
                PrimType::Bignumeric => Ok(DamlTypePayload::Bignumeric),
                PrimType::RoundingMode => Ok(DamlTypePayload::RoundingMode),
                PrimType::AnyException => Ok(DamlTypePayload::AnyException),
            },
            Sum::Con(con) => Ok(DamlTypePayload::TyCon(DamlTyConPayload::try_from(con)?)),
            Sum::Var(var) => Ok(DamlTypePayload::Var(DamlVarPayload::try_from(var)?)),
            Sum::Nat(n) =>
                if *n >= 0 && *n <= 37 {
                    #[allow(clippy::cast_possible_truncation)]
                    Ok(DamlTypePayload::Nat(*n as u8))
                } else {
                    Err(DamlLfConvertError::NatOutOfRange(*n))
                },
            Sum::Forall(forall) => Ok(DamlTypePayload::Forall(DamlForallPayload::try_from(forall.as_ref())?)),
            Sum::Struct(tuple) => Ok(DamlTypePayload::Struct(DamlStructPayload::try_from(tuple)?)),
            Sum::Syn(syn) => Ok(DamlTypePayload::Syn(DamlSynPayload::try_from(syn)?)),
            Sum::Interned(i) => Ok(DamlTypePayload::Interned(*i)),
        }
    }
}

pub type DamlSynWrapper<'a> = PayloadElementWrapper<'a, &'a DamlSynPayload<'a>>;

#[derive(Debug)]
pub struct DamlSynPayload<'a> {
    pub tysyn: DamlTypeSynNamePayload<'a>,
    pub args: Vec<DamlTypePayload<'a>>,
}

impl<'a> DamlSynPayload<'a> {
    pub fn new(tysyn: DamlTypeSynNamePayload<'a>, args: Vec<DamlTypePayload<'a>>) -> Self {
        Self {
            tysyn,
            args,
        }
    }
}

impl<'a> TryFrom<&'a Syn> for DamlSynPayload<'a> {
    type Error = DamlLfConvertError;

    fn try_from(syn: &'a Syn) -> DamlLfConvertResult<Self> {
        let tysyn = DamlTypeSynNamePayload::try_from(syn.tysyn.as_ref().req()?)?;
        let args = try_from_type_args(&syn.args)?;
        Ok(DamlSynPayload::new(tysyn, args))
    }
}

pub type DamlTypeSynNameWrapper<'a> = PayloadElementWrapper<'a, &'a DamlTypeSynNamePayload<'a>>;

#[derive(Debug)]
pub struct DamlTypeSynNamePayload<'a> {
    pub package_ref: DamlPackageRefPayload<'a>,
    pub module_path: InternableDottedName<'a>,
    pub data_name: InternableDottedName<'a>,
}

impl<'a> DamlTypeSynNamePayload<'a> {
    pub fn new(
        package_ref: DamlPackageRefPayload<'a>,
        module_path: InternableDottedName<'a>,
        data_name: InternableDottedName<'a>,
    ) -> Self {
        Self {
            package_ref,
            module_path,
            data_name,
        }
    }
}

impl<'a> TryFrom<&'a TypeSynName> for DamlTypeSynNamePayload<'a> {
    type Error = DamlLfConvertError;

    fn try_from(tysyn: &'a TypeSynName) -> DamlLfConvertResult<Self> {
        match tysyn {
            TypeSynName {
                module:
                    Some(ModuleRef {
                        package_ref: Some(package_ref),
                        module_name: Some(module_name),
                    }),
                name: Some(data_name),
            } => Ok(Self::new(
                package_ref.try_into()?,
                InternableDottedName::from(module_name),
                InternableDottedName::from(data_name),
            )),
            _ => Err(DamlLfConvertError::MissingRequiredField),
        }
    }
}

///
pub type DamlStructWrapper<'a> = PayloadElementWrapper<'a, &'a DamlStructPayload<'a>>;

#[derive(Debug)]
pub struct DamlStructPayload<'a> {
    pub fields: Vec<DamlFieldPayload<'a>>,
}

impl<'a> DamlStructPayload<'a> {
    pub fn new(fields: Vec<DamlFieldPayload<'a>>) -> Self {
        Self {
            fields,
        }
    }
}

impl<'a> TryFrom<&'a Struct> for DamlStructPayload<'a> {
    type Error = DamlLfConvertError;

    fn try_from(tuple: &'a Struct) -> DamlLfConvertResult<Self> {
        let fields = tuple.fields.iter().map(DamlFieldPayload::try_from).collect::<DamlLfConvertResult<Vec<_>>>()?;
        Ok(DamlStructPayload::new(fields))
    }
}

///
pub type DamlForallWrapper<'a> = PayloadElementWrapper<'a, &'a DamlForallPayload<'a>>;

#[derive(Debug)]
pub struct DamlForallPayload<'a> {
    pub vars: Vec<DamlTypeVarWithKindPayload<'a>>,
    pub body: Box<DamlTypePayload<'a>>,
}

impl<'a> DamlForallPayload<'a> {
    pub fn new(vars: Vec<DamlTypeVarWithKindPayload<'a>>, body: Box<DamlTypePayload<'a>>) -> Self {
        Self {
            vars,
            body,
        }
    }
}

impl<'a> TryFrom<&'a Forall> for DamlForallPayload<'a> {
    type Error = DamlLfConvertError;

    fn try_from(forall: &'a Forall) -> DamlLfConvertResult<Self> {
        let vars =
            forall.vars.iter().map(DamlTypeVarWithKindPayload::try_from).collect::<DamlLfConvertResult<Vec<_>>>()?;
        let body = DamlTypePayload::try_from(forall.body.as_ref().req()?.as_ref())?;
        Ok(DamlForallPayload::new(vars, Box::new(body)))
    }
}

///
pub type DamlTyConWrapper<'a> = PayloadElementWrapper<'a, &'a DamlTyConPayload<'a>>;

#[derive(Debug)]
pub struct DamlTyConPayload<'a> {
    pub package_ref: DamlPackageRefPayload<'a>,
    pub module_path: InternableDottedName<'a>,
    pub data_name: InternableDottedName<'a>,
    pub type_arguments: Vec<DamlTypePayload<'a>>,
}

impl<'a> DamlTyConPayload<'a> {
    pub fn new(
        package_ref: DamlPackageRefPayload<'a>,
        module_path: InternableDottedName<'a>,
        data_name: InternableDottedName<'a>,
        type_arguments: Vec<DamlTypePayload<'a>>,
    ) -> Self {
        Self {
            package_ref,
            module_path,
            data_name,
            type_arguments,
        }
    }
}

impl<'a> TryFrom<&'a Con> for DamlTyConPayload<'a> {
    type Error = DamlLfConvertError;

    fn try_from(con: &'a Con) -> DamlLfConvertResult<Self> {
        match con {
            Con {
                tycon:
                    Some(TypeConName {
                        module:
                            Some(ModuleRef {
                                package_ref: Some(package_ref),
                                module_name: Some(module_name),
                            }),
                        name: Some(data_name),
                    }),
                args,
            } => Ok(Self::new(
                package_ref.try_into()?,
                InternableDottedName::from(module_name),
                InternableDottedName::from(data_name),
                try_from_type_args(args)?,
            )),
            _ => Err(DamlLfConvertError::MissingRequiredField),
        }
    }
}

pub type DamlTyConNameWrapper<'a> = PayloadElementWrapper<'a, &'a DamlTyConNamePayload<'a>>;

#[derive(Debug)]
pub struct DamlTyConNamePayload<'a> {
    pub package_ref: DamlPackageRefPayload<'a>,
    pub module_path: InternableDottedName<'a>,
    pub data_name: InternableDottedName<'a>,
}

impl<'a> DamlTyConNamePayload<'a> {
    pub fn new(
        package_ref: DamlPackageRefPayload<'a>,
        module_path: InternableDottedName<'a>,
        data_name: InternableDottedName<'a>,
    ) -> Self {
        Self {
            package_ref,
            module_path,
            data_name,
        }
    }
}

impl<'a> TryFrom<&'a TypeConName> for DamlTyConNamePayload<'a> {
    type Error = DamlLfConvertError;

    fn try_from(con: &'a TypeConName) -> DamlLfConvertResult<Self> {
        match con {
            TypeConName {
                module:
                    Some(ModuleRef {
                        package_ref: Some(package_ref),
                        module_name: Some(module_name),
                    }),
                name: Some(data_name),
            } => Ok(Self::new(
                package_ref.try_into()?,
                InternableDottedName::from(module_name),
                InternableDottedName::from(data_name),
            )),
            _ => Err(DamlLfConvertError::MissingRequiredField),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum DamlPackageRefPayload<'a> {
    This,
    PackageId(&'a str),
    InternedId(i32),
}

impl<'a> DamlPackageRefPayload<'a> {
    pub fn resolve(&self, resolver: &'a impl PackageInternedResolver) -> DamlLfConvertResult<Cow<'a, str>> {
        Ok(match self {
            DamlPackageRefPayload::This => Cow::from(resolver.package_id()),
            &DamlPackageRefPayload::PackageId(s) => Cow::from(s),
            &DamlPackageRefPayload::InternedId(i) => resolver.resolve_string(i)?,
        })
    }
}

impl<'a> TryFrom<&'a PackageRef> for DamlPackageRefPayload<'a> {
    type Error = DamlLfConvertError;

    fn try_from(package_ref: &'a PackageRef) -> DamlLfConvertResult<Self> {
        Ok(match package_ref.sum.as_ref().req()? {
            package_ref::Sum::Self_(_) => DamlPackageRefPayload::This,
            package_ref::Sum::PackageIdStr(s) => DamlPackageRefPayload::PackageId(s.as_str()),
            &package_ref::Sum::PackageIdInternedStr(i) => DamlPackageRefPayload::InternedId(i),
        })
    }
}

///
pub type DamlVarWrapper<'a> = PayloadElementWrapper<'a, &'a DamlVarPayload<'a>>;

#[derive(Debug)]
pub struct DamlVarPayload<'a> {
    pub var: InternableString<'a>,
    pub type_arguments: Vec<DamlTypePayload<'a>>,
}

impl<'a> DamlVarPayload<'a> {
    pub fn new(var: InternableString<'a>, type_arguments: Vec<DamlTypePayload<'a>>) -> Self {
        Self {
            var,
            type_arguments,
        }
    }
}

impl<'a> TryFrom<&'a Var> for DamlVarPayload<'a> {
    type Error = DamlLfConvertError;

    fn try_from(var: &'a Var) -> DamlLfConvertResult<Self> {
        Ok(DamlVarPayload::new(InternableString::from(var.var.as_ref().req()?), try_from_type_args(&var.args)?))
    }
}

fn try_from_type_args(args: &[Type]) -> DamlLfConvertResult<Vec<DamlTypePayload<'_>>> {
    args.iter().map(DamlTypePayload::try_from).collect::<DamlLfConvertResult<Vec<_>>>()
}