daml_lf/element/
daml_module.rs

1use crate::element::daml_data::DamlData;
2use crate::element::visitor::DamlElementVisitor;
3#[cfg(feature = "full")]
4use crate::element::DamlDefValue;
5use crate::element::DamlVisitableElement;
6use crate::element::{serialize, DamlType, DamlTypeVarWithKind};
7use bounded_static::ToStatic;
8use itertools::Itertools;
9use serde::Serialize;
10use std::borrow::Cow;
11use std::collections::HashMap;
12use std::iter::once;
13
14const ROOT_MODULE_NAME: &str = "root";
15
16/// A Daml module.
17#[derive(Debug, Serialize, Clone, ToStatic)]
18pub struct DamlModule<'a> {
19    path: Vec<Cow<'a, str>>,
20    flags: DamlFeatureFlags,
21    synonyms: Vec<DamlDefTypeSyn<'a>>,
22    #[serde(serialize_with = "serialize::serialize_map")]
23    child_modules: HashMap<Cow<'a, str>, DamlModule<'a>>,
24    #[serde(serialize_with = "serialize::serialize_map")]
25    data_types: HashMap<Cow<'a, str>, DamlData<'a>>,
26    #[cfg(feature = "full")]
27    values: HashMap<Cow<'a, str>, DamlDefValue<'a>>,
28}
29
30impl<'a> DamlModule<'a> {
31    /// Create a root `DamlModule`.
32    pub fn new_root() -> Self {
33        Self::new_empty(vec![])
34    }
35
36    /// Create a leaf `DamlModule`.
37    pub fn new_leaf(
38        path: Vec<Cow<'a, str>>,
39        flags: DamlFeatureFlags,
40        synonyms: Vec<DamlDefTypeSyn<'a>>,
41        data_types: HashMap<Cow<'a, str>, DamlData<'a>>,
42        #[cfg(feature = "full")] values: HashMap<Cow<'a, str>, DamlDefValue<'a>>,
43    ) -> Self {
44        Self {
45            path,
46            flags,
47            synonyms,
48            child_modules: HashMap::default(),
49            data_types,
50            #[cfg(feature = "full")]
51            values,
52        }
53    }
54
55    /// The `DamlFeatureFlags` of the module.
56    pub fn flags(&self) -> &DamlFeatureFlags {
57        &self.flags
58    }
59
60    /// The `DamlDefTypeSyn` of the module.
61    pub fn synonyms(&self) -> &[DamlDefTypeSyn<'_>] {
62        &self.synonyms
63    }
64
65    /// The module path.
66    pub fn path(&self) -> impl Iterator<Item = &str> {
67        self.path.iter().map(AsRef::as_ref)
68    }
69
70    /// The child `DamlModule` of the module.
71    pub fn child_modules(&self) -> impl Iterator<Item = &DamlModule<'a>> {
72        self.child_modules.values()
73    }
74
75    /// The `DamlData` declared in the module.
76    pub fn data_types(&self) -> impl Iterator<Item = &DamlData<'a>> {
77        self.data_types.values()
78    }
79
80    /// The `DamlDefValue` declared in the module.
81    #[cfg(feature = "full")]
82    pub fn values(&self) -> impl Iterator<Item = &DamlDefValue<'a>> {
83        self.values.values()
84    }
85
86    /// Returns `true` if this is a root module, `false` otherwise.
87    pub fn is_root(&self) -> bool {
88        self.path.is_empty()
89    }
90
91    /// Returns `true` if this is a leaf module, `false` otherwise.
92    pub fn is_leaf(&self) -> bool {
93        self.child_modules.is_empty()
94    }
95
96    /// Returns the local name of the module.
97    pub fn local_name(&self) -> &str {
98        self.path.last().map(AsRef::as_ref).map_or_else(|| ROOT_MODULE_NAME, AsRef::as_ref)
99    }
100
101    /// Retrieve a child [`DamlModule`] by name or `None` if no such module exists.
102    pub fn child_module<S: AsRef<str>>(&self, name: S) -> Option<&DamlModule<'_>> {
103        self.child_modules.get(name.as_ref())
104    }
105
106    /// Retrieve a child [`DamlModule`] by name or `None` if no such module exists.
107    pub fn child_module_path<'b, S: AsRef<str>>(&'a self, relative_path: &'b [S]) -> Option<&'a DamlModule<'a>> {
108        match relative_path {
109            [] => Some(self),
110            [head, tail @ ..] => match self.child_module(head.as_ref()) {
111                Some(m) => m.child_module_path(tail),
112                None => None,
113            },
114        }
115    }
116
117    /// Retrieve a [`DamlData`] by name or `None` if no such data type exists.
118    pub fn data_type<S: AsRef<str>>(&self, name: S) -> Option<&DamlData<'a>> {
119        self.data_types.get(name.as_ref())
120    }
121
122    /// Retrieve a [`DamlDefValue`] by name or `None` if no such value exists.
123    #[cfg(feature = "full")]
124    pub fn value<S: AsRef<str>>(&self, name: S) -> Option<&DamlDefValue<'a>> {
125        self.values.get(name.as_ref())
126    }
127
128    /// Retrieve or create a child [`DamlModule`] with `name`.
129    #[doc(hidden)]
130    pub(crate) fn child_module_or_new(&mut self, name: &'a str) -> &mut Self {
131        let path = &self.path;
132        self.child_modules.entry(Cow::from(name)).or_insert_with(|| {
133            DamlModule::new_empty(path.iter().map(ToOwned::to_owned).chain(once(Cow::from(name))).collect())
134        })
135    }
136
137    /// Populate this module with data taken from another module.
138    ///
139    /// Note that this does not copy the `child_modules` from the `other` [`DamlModule`] as this node may already have
140    /// existing children.
141    #[doc(hidden)]
142    pub(crate) fn take_from(&mut self, other: Self) {
143        debug_assert_eq!(self.path, other.path);
144        self.flags = other.flags;
145        self.data_types = other.data_types;
146        self.synonyms = other.synonyms;
147        #[cfg(feature = "full")]
148        {
149            self.values = other.values;
150        }
151    }
152
153    /// Create an empty `DamlModule` with a given `path`.
154    fn new_empty(path: Vec<Cow<'a, str>>) -> Self {
155        Self {
156            path,
157            flags: DamlFeatureFlags::default(),
158            synonyms: Vec::default(),
159            child_modules: HashMap::default(),
160            data_types: HashMap::default(),
161            #[cfg(feature = "full")]
162            values: HashMap::default(),
163        }
164    }
165}
166
167impl<'a> DamlVisitableElement<'a> for DamlModule<'a> {
168    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
169        visitor.pre_visit_module(self);
170        self.synonyms.iter().for_each(|syn| syn.accept(visitor));
171        if visitor.sort_elements() {
172            self.data_types.values().sorted_by_key(|ty| ty.name()).for_each(|data| data.accept(visitor));
173            self.child_modules.values().sorted_by_key(|&m| m.path.clone()).for_each(|module| module.accept(visitor));
174        } else {
175            self.data_types.values().for_each(|data| data.accept(visitor));
176            self.child_modules.values().for_each(|module| module.accept(visitor));
177        }
178        #[cfg(feature = "full")]
179        self.values.values().for_each(|value| value.accept(visitor));
180        visitor.post_visit_module(self);
181    }
182}
183
184/// A Daml Type synonym definition.
185#[derive(Debug, Serialize, Clone, ToStatic)]
186pub struct DamlDefTypeSyn<'a> {
187    params: Vec<DamlTypeVarWithKind<'a>>,
188    ty: DamlType<'a>,
189    name: Vec<Cow<'a, str>>,
190}
191
192impl<'a> DamlDefTypeSyn<'a> {
193    /// Create a type synonym.
194    pub fn new(params: Vec<DamlTypeVarWithKind<'a>>, ty: DamlType<'a>, name: Vec<Cow<'a, str>>) -> Self {
195        Self {
196            params,
197            ty,
198            name,
199        }
200    }
201
202    ///
203    pub fn params(&self) -> &[DamlTypeVarWithKind<'_>] {
204        &self.params
205    }
206
207    /// Type of the defined type synonym.
208    pub fn ty(&self) -> &DamlType<'_> {
209        &self.ty
210    }
211
212    /// Name of the defined type synonym.
213    pub fn name(&self) -> impl Iterator<Item = &str> {
214        self.name.iter().map(AsRef::as_ref)
215    }
216}
217
218impl<'a> DamlVisitableElement<'a> for DamlDefTypeSyn<'a> {
219    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
220        visitor.pre_visit_def_type_syn(self);
221        self.params.iter().for_each(|param| param.accept(visitor));
222        self.ty.accept(visitor);
223        visitor.post_visit_def_type_syn(self);
224    }
225}
226
227/// Daml Feature flags.
228#[derive(Debug, Serialize, Copy, Clone, Default, ToStatic)]
229pub struct DamlFeatureFlags {
230    forbid_party_literals: bool,
231    dont_divulge_contract_ids_in_create_arguments: bool,
232    dont_disclose_non_consuming_choices_to_observers: bool,
233}
234
235impl DamlFeatureFlags {
236    pub fn new(
237        forbid_party_literals: bool,
238        dont_divulge_contract_ids_in_create_arguments: bool,
239        dont_disclose_non_consuming_choices_to_observers: bool,
240    ) -> Self {
241        Self {
242            forbid_party_literals,
243            dont_divulge_contract_ids_in_create_arguments,
244            dont_disclose_non_consuming_choices_to_observers,
245        }
246    }
247
248    ///
249    pub fn forbid_party_literals(self) -> bool {
250        self.forbid_party_literals
251    }
252
253    ///
254    pub fn dont_divulge_contract_ids_in_create_arguments(self) -> bool {
255        self.dont_divulge_contract_ids_in_create_arguments
256    }
257
258    ///
259    pub fn dont_disclose_non_consuming_choices_to_observers(self) -> bool {
260        self.dont_disclose_non_consuming_choices_to_observers
261    }
262}