1use crate::data::DamlError;
2use crate::nat::{Nat, Nat10};
3use bigdecimal::BigDecimal;
4use chrono::{Date, DateTime, Utc};
5use itertools::Itertools;
6use std::cmp::Ordering;
7use std::collections::{BTreeMap, HashMap};
8use std::convert::TryFrom;
9use std::fmt::Formatter;
10use std::iter::FromIterator;
11use std::marker::PhantomData;
12use std::ops::{Deref, DerefMut};
13use std::str::FromStr;
14
15pub type DamlInt64 = i64;
17
18pub type DamlNumeric = BigDecimal;
20
21pub type DamlNumeric10 = DamlFixedNumeric<Nat10>;
23
24pub type DamlText = String;
26
27pub type DamlTimestamp = DateTime<Utc>;
29
30pub type DamlBool = bool;
32
33pub type DamlUnit = ();
35
36pub type DamlDate = Date<Utc>;
38
39pub type DamlList<T> = Vec<T>;
41
42pub type DamlTextMap<V> = DamlTextMapImpl<V>;
44
45pub type DamlGenMap<K, V> = BTreeMap<K, V>;
47
48pub type DamlOptional<T> = Option<T>;
50
51#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone)]
53pub struct DamlParty {
54 pub party: String,
55}
56
57impl DamlParty {
58 pub fn new(party: impl Into<String>) -> Self {
59 Self {
60 party: party.into(),
61 }
62 }
63
64 pub fn as_str(&self) -> &str {
65 self.party.as_str()
66 }
67}
68
69impl From<&str> for DamlParty {
70 fn from(party: &str) -> Self {
71 DamlParty::new(party)
72 }
73}
74
75impl From<String> for DamlParty {
76 fn from(party: String) -> Self {
77 DamlParty::new(party)
78 }
79}
80
81impl PartialEq<&DamlParty> for &str {
82 fn eq(&self, other: &&DamlParty) -> bool {
83 *self == other.party
84 }
85}
86
87impl PartialEq<&str> for &DamlParty {
88 fn eq(&self, other: &&str) -> bool {
89 self.party == *other
90 }
91}
92
93impl PartialEq<DamlParty> for &str {
94 fn eq(&self, other: &DamlParty) -> bool {
95 self == &other.party
96 }
97}
98
99impl PartialEq<&str> for DamlParty {
100 fn eq(&self, other: &&str) -> bool {
101 &self.party == other
102 }
103}
104
105impl std::fmt::Display for DamlParty {
106 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
107 self.party.fmt(f)
108 }
109}
110
111#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone)]
113pub struct DamlContractId {
114 pub contract_id: String,
115}
116
117impl DamlContractId {
118 pub fn new(contract_id: impl Into<String>) -> Self {
119 Self {
120 contract_id: contract_id.into(),
121 }
122 }
123
124 pub fn as_str(&self) -> &str {
125 self.contract_id.as_str()
126 }
127}
128
129impl From<&str> for DamlContractId {
130 fn from(contract_id: &str) -> Self {
131 DamlContractId::new(contract_id)
132 }
133}
134
135impl From<String> for DamlContractId {
136 fn from(contract_id: String) -> Self {
137 DamlContractId::new(contract_id)
138 }
139}
140
141impl PartialEq<&DamlContractId> for &str {
142 fn eq(&self, other: &&DamlContractId) -> bool {
143 *self == other.contract_id
144 }
145}
146
147impl PartialEq<&str> for &DamlContractId {
148 fn eq(&self, other: &&str) -> bool {
149 self.contract_id == *other
150 }
151}
152
153impl PartialEq<DamlContractId> for &str {
154 fn eq(&self, other: &DamlContractId) -> bool {
155 self == &other.contract_id
156 }
157}
158
159impl PartialEq<&str> for DamlContractId {
160 fn eq(&self, other: &&str) -> bool {
161 &self.contract_id == other
162 }
163}
164
165impl std::fmt::Display for DamlContractId {
166 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
167 self.contract_id.fmt(f)
168 }
169}
170
171#[derive(Debug, Eq, Default, Clone)]
173pub struct DamlTextMapImpl<T>(pub HashMap<DamlText, T>);
174
175impl<T> DamlTextMapImpl<T> {
176 pub fn new() -> Self {
177 DamlTextMapImpl(HashMap::new())
178 }
179}
180
181impl<T: PartialEq> PartialOrd for DamlTextMapImpl<T> {
186 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
187 if self.0.len() != other.0.len() {
188 return self.0.len().partial_cmp(&other.0.len());
189 }
190 self.0.keys().sorted().partial_cmp(other.0.keys().sorted())
191 }
192}
193
194impl<T: PartialOrd + Ord> Ord for DamlTextMapImpl<T> {
195 fn cmp(&self, other: &Self) -> Ordering {
196 self.partial_cmp(other).expect("PartialOrd is never None")
197 }
198}
199
200impl<T> PartialEq for DamlTextMapImpl<T> {
205 fn eq(&self, other: &Self) -> bool {
206 if self.0.len() != other.0.len() {
207 return false;
208 }
209 self.0.keys().all(|key| other.get(key).is_some())
210 }
211}
212
213impl<T> From<HashMap<DamlText, T>> for DamlTextMapImpl<T> {
214 fn from(m: HashMap<DamlText, T>) -> Self {
215 Self(m)
216 }
217}
218
219impl<T> Deref for DamlTextMapImpl<T> {
220 type Target = HashMap<DamlText, T>;
221
222 fn deref(&self) -> &Self::Target {
223 &self.0
224 }
225}
226
227impl<T> DerefMut for DamlTextMapImpl<T> {
228 fn deref_mut(&mut self) -> &mut Self::Target {
229 &mut self.0
230 }
231}
232
233impl<V> IntoIterator for DamlTextMapImpl<V> {
234 type IntoIter = <HashMap<DamlText, V> as IntoIterator>::IntoIter;
235 type Item = (DamlText, V);
236
237 fn into_iter(self) -> Self::IntoIter {
238 HashMap::into_iter(self.0)
239 }
240}
241
242impl<V> FromIterator<(DamlText, V)> for DamlTextMapImpl<V> {
243 fn from_iter<T: IntoIterator<Item = (DamlText, V)>>(iter: T) -> DamlTextMapImpl<V> {
244 Self::from(HashMap::from_iter(iter))
245 }
246}
247
248#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
250pub struct DamlFixedNumeric<T: Nat> {
251 pub _phantom: PhantomData<T>,
252 pub value: BigDecimal,
253}
254
255impl<T: Nat> DamlFixedNumeric<T> {
256 pub fn new(value: BigDecimal) -> Self {
257 Self {
258 _phantom: PhantomData::<T>::default(),
259 value,
260 }
261 }
262
263 pub fn try_new(f: f64) -> Result<Self, DamlError> {
264 Ok(Self::new(BigDecimal::try_from(f)?))
265 }
266}
267
268#[allow(clippy::fallible_impl_from)]
276impl<T: Nat> From<f64> for DamlFixedNumeric<T> {
277 fn from(f: f64) -> Self {
278 Self::new(match BigDecimal::try_from(f) {
279 Ok(bd) => bd,
280 Err(err) => panic!("invalid f64: {}", err),
281 })
282 }
283}
284
285impl<T: Nat> FromStr for DamlFixedNumeric<T> {
286 type Err = DamlError;
287
288 fn from_str(s: &str) -> Result<Self, Self::Err> {
289 Ok(Self::new(FromStr::from_str(s)?))
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296
297 #[test]
298 fn test_numeric_try_new() {
299 let num = DamlNumeric10::try_new(1.2_f64).unwrap();
300 assert_eq!(DamlNumeric10::new(BigDecimal::try_from(1.2_f64).unwrap()), num);
301 }
302
303 #[test]
304 fn test_numeric_try_new_nan() {
305 let num = DamlNumeric10::try_new(1_f64 / 0_f64);
306 assert!(num.is_err());
307 }
308
309 #[test]
310 fn test_numeric_from() {
311 let num = DamlNumeric10::from(1.2_f64);
312 assert_eq!(DamlNumeric10::new(BigDecimal::try_from(1.2_f64).unwrap()), num);
313 }
314
315 #[test]
316 #[should_panic]
317 fn test_numeric_from_should_panic() {
318 let _panic = DamlNumeric10::from(1_f64 / 0_f64);
319 }
320
321 #[test]
322 fn test_daml_text_map_equal_keys() {
323 let map1: DamlTextMapImpl<DamlInt64> =
324 vec![("key1".into(), 10), ("key2".into(), 20)].into_iter().collect::<DamlTextMap<DamlInt64>>();
325 let map2: DamlTextMap<DamlInt64> =
326 vec![("key1".into(), 100), ("key2".into(), 200)].into_iter().collect::<DamlTextMap<DamlInt64>>();
327 assert_eq!(map1, map2);
328 }
329
330 #[test]
331 fn test_daml_text_map_not_equal_keys() {
332 let map1: DamlTextMap<DamlInt64> =
333 vec![("key1".into(), 10), ("key2".into(), 20)].into_iter().collect::<DamlTextMap<DamlInt64>>();
334 let map2: DamlTextMap<DamlInt64> =
335 vec![("key3".into(), 10), ("key4".into(), 20)].into_iter().collect::<DamlTextMap<DamlInt64>>();
336 assert_ne!(map1, map2);
337 }
338
339 #[test]
340 fn test_daml_text_map_order() {
341 let map1: DamlTextMap<DamlInt64> =
342 vec![("key1".into(), 10), ("key2".into(), 20)].into_iter().collect::<DamlTextMap<DamlInt64>>();
343 let map2: DamlTextMap<DamlInt64> =
344 vec![("key2".into(), 10), ("key3".into(), 20)].into_iter().collect::<DamlTextMap<DamlInt64>>();
345 let map3: DamlTextMap<DamlInt64> =
346 vec![("key1".into(), 100), ("key2".into(), 200)].into_iter().collect::<DamlTextMap<DamlInt64>>();
347 assert_eq!(Ordering::Less, map1.cmp(&map2));
348 assert_eq!(Ordering::Greater, map2.cmp(&map1));
349 assert_eq!(Ordering::Equal, map1.cmp(&map3));
350 }
351}