1use std::collections::BTreeMap;
4use std::fmt;
5use std::marker::PhantomData;
6
7#[derive(
21 Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
22)]
23#[serde(transparent)]
24pub struct Party(pub(crate) String);
25
26const PARTY_MAX_LEN: usize = 255;
28
29const fn is_party_char(c: char) -> bool {
32 c.is_ascii_alphanumeric() || matches!(c, ':' | '-' | '_' | ' ')
33}
34
35impl Party {
36 #[must_use]
40 pub fn new(id: impl Into<String>) -> Self {
41 Self(id.into())
42 }
43
44 pub fn parse(id: impl Into<String>) -> Result<Self, PartyParseError> {
51 let id = id.into();
52 if id.is_empty() {
53 return Err(PartyParseError::Empty);
54 }
55 if id.chars().count() > PARTY_MAX_LEN {
56 return Err(PartyParseError::TooLong {
57 length: id.chars().count(),
58 });
59 }
60 if let Some(c) = id.chars().find(|c| !is_party_char(*c)) {
61 return Err(PartyParseError::UnexpectedCharacter { character: c });
62 }
63 Ok(Self(id))
64 }
65
66 #[must_use]
68 pub fn as_str(&self) -> &str {
69 &self.0
70 }
71
72 #[must_use]
74 pub fn into_string(self) -> String {
75 self.0
76 }
77}
78
79impl fmt::Display for Party {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f.write_str(&self.0)
82 }
83}
84
85impl AsRef<str> for Party {
86 fn as_ref(&self) -> &str {
87 &self.0
88 }
89}
90
91impl From<String> for Party {
92 fn from(id: String) -> Self {
93 Self(id)
94 }
95}
96
97impl From<&str> for Party {
98 fn from(id: &str) -> Self {
99 Self::new(id)
100 }
101}
102
103impl From<Party> for String {
104 fn from(party: Party) -> Self {
105 party.0
106 }
107}
108
109pub struct ContractId<T> {
115 id: String,
116 _marker: PhantomData<fn() -> T>,
117}
118
119impl<T> ContractId<T> {
120 #[must_use]
122 pub fn new(id: impl Into<String>) -> Self {
123 Self {
124 id: id.into(),
125 _marker: PhantomData,
126 }
127 }
128
129 #[must_use]
131 pub fn as_str(&self) -> &str {
132 &self.id
133 }
134
135 #[must_use]
143 pub fn retag<U>(self) -> ContractId<U> {
144 ContractId::new(self.id)
145 }
146}
147
148impl<T> Clone for ContractId<T> {
149 fn clone(&self) -> Self {
150 Self::new(self.id.clone())
151 }
152}
153
154impl<T> fmt::Debug for ContractId<T> {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 f.debug_tuple("ContractId").field(&self.id).finish()
157 }
158}
159
160impl<T> PartialEq for ContractId<T> {
161 fn eq(&self, other: &Self) -> bool {
162 self.id == other.id
163 }
164}
165
166impl<T> Eq for ContractId<T> {}
167
168impl<T> std::hash::Hash for ContractId<T> {
169 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
170 self.id.hash(state);
171 }
172}
173
174impl<T> PartialOrd for ContractId<T> {
175 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
176 Some(self.cmp(other))
177 }
178}
179
180impl<T> Ord for ContractId<T> {
181 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
182 self.id.cmp(&other.id)
183 }
184}
185
186#[derive(Clone, Debug)]
211pub struct Numeric(pub(crate) String);
212
213impl Numeric {
214 pub fn parse(text: impl Into<String>) -> Result<Self, NumericParseError> {
221 let text = text.into();
222 if canonical_decimal(&text).is_some() {
223 Ok(Self(text))
224 } else {
225 Err(NumericParseError { input: text })
226 }
227 }
228
229 #[must_use]
233 pub fn from_wire(text: impl Into<String>) -> Self {
234 Self(text.into())
235 }
236
237 #[must_use]
239 pub fn as_str(&self) -> &str {
240 &self.0
241 }
242
243 fn canonical(&self) -> Option<String> {
246 canonical_decimal(&self.0)
247 }
248}
249
250#[derive(Clone, Debug, PartialEq, Eq)]
256#[non_exhaustive]
257pub enum PartyParseError {
258 Empty,
261 TooLong {
263 length: usize,
265 },
266 UnexpectedCharacter {
268 character: char,
270 },
271}
272
273impl fmt::Display for PartyParseError {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 match self {
278 Self::Empty => f.write_str("a party id cannot be empty"),
279 Self::TooLong { length } => write!(
280 f,
281 "a party id cannot exceed {PARTY_MAX_LEN} characters (got {length})"
282 ),
283 Self::UnexpectedCharacter { character } => write!(
284 f,
285 "`{character}` is not valid in a party id \
286 (expected letters, digits, `:`, `-`, `_`, space)"
287 ),
288 }
289 }
290}
291
292impl std::error::Error for PartyParseError {}
293
294impl std::str::FromStr for Party {
295 type Err = PartyParseError;
296 fn from_str(id: &str) -> Result<Self, Self::Err> {
297 Self::parse(id)
298 }
299}
300
301#[derive(Clone, Debug, PartialEq, Eq)]
303pub struct NumericParseError {
304 input: String,
305}
306
307impl NumericParseError {
308 #[must_use]
310 pub fn input(&self) -> &str {
311 &self.input
312 }
313}
314
315impl fmt::Display for NumericParseError {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 write!(
318 f,
319 "`{}` is not a decimal literal (expected -?digits[.digits])",
320 self.input
321 )
322 }
323}
324
325impl std::error::Error for NumericParseError {}
326
327impl std::str::FromStr for Numeric {
328 type Err = NumericParseError;
329 fn from_str(text: &str) -> Result<Self, Self::Err> {
330 Self::parse(text)
331 }
332}
333
334impl fmt::Display for Numeric {
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 f.write_str(&self.0)
337 }
338}
339
340impl TryFrom<&str> for Numeric {
341 type Error = NumericParseError;
342 fn try_from(text: &str) -> Result<Self, Self::Error> {
343 Self::parse(text)
344 }
345}
346
347fn canonical_decimal(raw: &str) -> Option<String> {
351 let (negative, digits) = match raw.strip_prefix('-') {
352 Some(rest) => (true, rest),
353 None => (false, raw.strip_prefix('+').unwrap_or(raw)),
354 };
355 let (int, frac) = digits.split_once('.').unwrap_or((digits, ""));
356 let valid = !int.is_empty()
359 && int.bytes().all(|b| b.is_ascii_digit())
360 && frac.bytes().all(|b| b.is_ascii_digit());
361 if !valid {
362 return None;
363 }
364 let int = int.trim_start_matches('0');
365 let int = if int.is_empty() { "0" } else { int };
366 let frac = frac.trim_end_matches('0');
367 let mut canonical = String::with_capacity(raw.len() + 1);
368 if negative && !(int == "0" && frac.is_empty()) {
369 canonical.push('-');
370 }
371 canonical.push_str(int);
372 if !frac.is_empty() {
373 canonical.push('.');
374 canonical.push_str(frac);
375 }
376 Some(canonical)
377}
378
379impl PartialEq for Numeric {
380 fn eq(&self, other: &Self) -> bool {
381 match (self.canonical(), other.canonical()) {
382 (Some(a), Some(b)) => a == b,
383 (None, None) => self.0 == other.0,
384 _ => false,
385 }
386 }
387}
388
389impl Eq for Numeric {}
390
391impl std::hash::Hash for Numeric {
392 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
393 match self.canonical() {
395 Some(canonical) => canonical.hash(state),
396 None => self.0.hash(state),
397 }
398 }
399}
400
401impl PartialOrd for Numeric {
402 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
403 Some(self.cmp(other))
404 }
405}
406
407impl Ord for Numeric {
408 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
409 use std::cmp::Ordering;
410 let (Some(a), Some(b)) = (self.canonical(), other.canonical()) else {
411 return match (self.canonical(), other.canonical()) {
414 (Some(_), None) => Ordering::Less,
415 (None, Some(_)) => Ordering::Greater,
416 _ => self.0.cmp(&other.0),
417 };
418 };
419 let (neg_a, mag_a) = a
420 .strip_prefix('-')
421 .map_or((false, a.as_str()), |m| (true, m));
422 let (neg_b, mag_b) = b
423 .strip_prefix('-')
424 .map_or((false, b.as_str()), |m| (true, m));
425 match (neg_a, neg_b) {
426 (false, true) => Ordering::Greater,
427 (true, false) => Ordering::Less,
428 (negative, _) => {
429 let ordering = magnitude_cmp(mag_a, mag_b);
430 if negative {
431 ordering.reverse()
432 } else {
433 ordering
434 }
435 }
436 }
437 }
438}
439
440fn magnitude_cmp(a: &str, b: &str) -> std::cmp::Ordering {
445 let (int_a, frac_a) = a.split_once('.').unwrap_or((a, ""));
446 let (int_b, frac_b) = b.split_once('.').unwrap_or((b, ""));
447 int_a
448 .len()
449 .cmp(&int_b.len())
450 .then_with(|| int_a.cmp(int_b))
451 .then_with(|| frac_a.cmp(frac_b))
452}
453
454impl serde::Serialize for Numeric {
455 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
456 serializer.serialize_str(&self.0)
457 }
458}
459
460impl<'de> serde::Deserialize<'de> for Numeric {
461 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
462 struct NumericVisitor;
463 impl serde::de::Visitor<'_> for NumericVisitor {
464 type Value = Numeric;
465 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466 f.write_str("a Daml Numeric as a decimal string or a JSON number")
467 }
468 fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Numeric, E> {
469 Ok(Numeric(value.to_string()))
470 }
471 fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Numeric, E> {
472 Ok(Numeric(value.to_string()))
473 }
474 fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Numeric, E> {
475 Ok(Numeric(value.to_string()))
476 }
477 fn visit_f64<E: serde::de::Error>(self, value: f64) -> Result<Numeric, E> {
478 Ok(Numeric(value.to_string()))
479 }
480 }
481 deserializer.deserialize_any(NumericVisitor)
482 }
483}
484
485#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
492pub struct Int64(pub i64);
493
494impl From<i64> for Int64 {
495 fn from(value: i64) -> Self {
496 Self(value)
497 }
498}
499
500impl From<Int64> for i64 {
501 fn from(value: Int64) -> Self {
502 value.0
503 }
504}
505
506impl fmt::Display for Int64 {
507 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
508 write!(f, "{}", self.0)
509 }
510}
511
512impl std::str::FromStr for Int64 {
513 type Err = std::num::ParseIntError;
514 fn from_str(text: &str) -> Result<Self, Self::Err> {
515 text.parse().map(Self)
516 }
517}
518
519impl serde::Serialize for Int64 {
520 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
521 serializer.serialize_str(&self.0.to_string())
522 }
523}
524
525impl<'de> serde::Deserialize<'de> for Int64 {
526 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
527 struct Int64Visitor;
528 impl serde::de::Visitor<'_> for Int64Visitor {
529 type Value = Int64;
530 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
531 f.write_str("an Int64 as a JSON number or a string")
532 }
533 fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Int64, E> {
534 Ok(Int64(value))
535 }
536 fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Int64, E> {
537 i64::try_from(value)
538 .map(Int64)
539 .map_err(serde::de::Error::custom)
540 }
541 fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Int64, E> {
542 value
543 .parse::<i64>()
544 .map(Int64)
545 .map_err(serde::de::Error::custom)
546 }
547 }
548 deserializer.deserialize_any(Int64Visitor)
549 }
550}
551
552#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
565pub struct Timestamp(pub i64);
566
567impl Timestamp {
568 #[must_use]
570 pub fn micros(self) -> i64 {
571 self.0
572 }
573
574 #[must_use]
577 pub fn to_datetime(self) -> Option<time::OffsetDateTime> {
578 time::OffsetDateTime::from_unix_timestamp_nanos(i128::from(self.0) * 1_000).ok()
579 }
580
581 #[must_use]
587 pub fn from_datetime(at: time::OffsetDateTime) -> Option<Self> {
588 let micros = at.unix_timestamp_nanos().div_euclid(1_000);
589 i64::try_from(micros).ok().map(Self)
590 }
591}
592
593impl From<Timestamp> for i64 {
594 fn from(at: Timestamp) -> Self {
595 at.0
596 }
597}
598
599#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
603pub struct Date(pub i32);
604
605impl Date {
606 #[must_use]
608 pub fn days(self) -> i32 {
609 self.0
610 }
611
612 #[must_use]
615 pub fn to_date(self) -> Option<time::Date> {
616 UNIX_EPOCH_DATE.checked_add(time::Duration::days(i64::from(self.0)))
617 }
618
619 #[must_use]
629 pub fn from_date(date: time::Date) -> Option<Self> {
630 i32::try_from((date - UNIX_EPOCH_DATE).whole_days())
631 .ok()
632 .map(Self)
633 }
634}
635
636impl From<Date> for i32 {
637 fn from(date: Date) -> Self {
638 date.0
639 }
640}
641
642pub type TextMap<V> = BTreeMap<String, V>;
644
645#[derive(Clone, Debug, Eq, serde::Serialize, serde::Deserialize)]
651#[serde(transparent)]
652pub struct GenMap<K, V>(pub(crate) Vec<(K, V)>);
653
654impl<K, V> Default for GenMap<K, V> {
659 fn default() -> Self {
660 Self(Vec::new())
661 }
662}
663
664impl<K, V> GenMap<K, V> {
665 #[must_use]
667 pub fn new() -> Self {
668 Self(Vec::new())
669 }
670
671 pub fn iter(&self) -> std::slice::Iter<'_, (K, V)> {
673 self.0.iter()
674 }
675
676 #[must_use]
678 pub fn len(&self) -> usize {
679 self.0.len()
680 }
681
682 #[must_use]
684 pub fn is_empty(&self) -> bool {
685 self.0.is_empty()
686 }
687
688 pub fn insert(&mut self, key: K, value: V) {
691 self.0.push((key, value));
692 }
693}
694
695impl<K, V> From<Vec<(K, V)>> for GenMap<K, V> {
696 fn from(entries: Vec<(K, V)>) -> Self {
697 Self(entries)
698 }
699}
700
701impl<K, V> FromIterator<(K, V)> for GenMap<K, V> {
702 fn from_iter<I: IntoIterator<Item = (K, V)>>(entries: I) -> Self {
703 Self(entries.into_iter().collect())
704 }
705}
706
707impl<K, V> IntoIterator for GenMap<K, V> {
708 type Item = (K, V);
709 type IntoIter = std::vec::IntoIter<(K, V)>;
710 fn into_iter(self) -> Self::IntoIter {
711 self.0.into_iter()
712 }
713}
714
715impl<'a, K, V> IntoIterator for &'a GenMap<K, V> {
716 type Item = &'a (K, V);
717 type IntoIter = std::slice::Iter<'a, (K, V)>;
718 fn into_iter(self) -> Self::IntoIter {
719 self.0.iter()
720 }
721}
722
723impl<K: PartialEq, V: PartialEq> PartialEq for GenMap<K, V> {
729 fn eq(&self, other: &Self) -> bool {
730 if self.0.len() != other.0.len() {
731 return false;
732 }
733 let mut matched = vec![false; other.0.len()];
736 self.0.iter().all(|entry| {
737 other
738 .0
739 .iter()
740 .enumerate()
741 .position(|(index, candidate)| !matched[index] && candidate == entry)
742 .is_some_and(|index| {
743 matched[index] = true;
744 true
745 })
746 })
747 }
748}
749
750const UNIX_EPOCH_DATE: time::Date = time::macros::date!(1970 - 01 - 01);
752
753const DATE_FORMAT: &[time::format_description::FormatItem<'static>] =
755 time::macros::format_description!("[year]-[month]-[day]");
756
757impl<T> serde::Serialize for ContractId<T> {
762 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
763 serializer.serialize_str(&self.id)
764 }
765}
766
767impl<'de, T> serde::Deserialize<'de> for ContractId<T> {
768 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
769 Ok(Self::new(String::deserialize(deserializer)?))
770 }
771}
772
773impl serde::Serialize for Timestamp {
774 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
775 let datetime = time::OffsetDateTime::from_unix_timestamp_nanos(i128::from(self.0) * 1_000)
776 .map_err(serde::ser::Error::custom)?;
777 let text = datetime
778 .format(&time::format_description::well_known::Rfc3339)
779 .map_err(serde::ser::Error::custom)?;
780 serializer.serialize_str(&text)
781 }
782}
783
784impl<'de> serde::Deserialize<'de> for Timestamp {
785 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
786 let text = String::deserialize(deserializer)?;
787 let datetime =
788 time::OffsetDateTime::parse(&text, &time::format_description::well_known::Rfc3339)
789 .map_err(serde::de::Error::custom)?;
790 let micros = datetime.unix_timestamp_nanos().div_euclid(1_000);
794 Ok(Self(
795 i64::try_from(micros).map_err(serde::de::Error::custom)?,
796 ))
797 }
798}
799
800impl serde::Serialize for Date {
801 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
802 let date = UNIX_EPOCH_DATE
803 .checked_add(time::Duration::days(i64::from(self.0)))
804 .ok_or_else(|| serde::ser::Error::custom("date out of range"))?;
805 let text = date
806 .format(DATE_FORMAT)
807 .map_err(serde::ser::Error::custom)?;
808 serializer.serialize_str(&text)
809 }
810}
811
812impl<'de> serde::Deserialize<'de> for Date {
813 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
814 let text = String::deserialize(deserializer)?;
815 let date = time::Date::parse(&text, DATE_FORMAT).map_err(serde::de::Error::custom)?;
816 let days = (date - UNIX_EPOCH_DATE).whole_days();
817 Ok(Self(i32::try_from(days).map_err(serde::de::Error::custom)?))
818 }
819}
820
821#[derive(Clone, Debug, PartialEq, Eq, Default)]
840pub struct NestedOpt<T>(pub Option<T>);
841
842impl<T> NestedOpt<T> {
843 #[must_use]
845 pub fn new(value: Option<T>) -> Self {
846 Self(value)
847 }
848
849 #[must_use]
851 pub fn into_inner(self) -> Option<T> {
852 self.0
853 }
854}
855
856impl<T> From<Option<T>> for NestedOpt<T> {
857 fn from(value: Option<T>) -> Self {
858 Self(value)
859 }
860}
861
862impl<T> From<NestedOpt<T>> for Option<T> {
863 fn from(value: NestedOpt<T>) -> Self {
864 value.0
865 }
866}
867
868impl<T: serde::Serialize> serde::Serialize for NestedOpt<T> {
869 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
870 match &self.0 {
873 None => serializer.collect_seq(core::iter::empty::<&T>()),
874 Some(value) => serializer.collect_seq(core::iter::once(value)),
875 }
876 }
877}
878
879impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for NestedOpt<T> {
880 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
881 let mut items = Vec::<T>::deserialize(deserializer)?;
882 match items.len() {
883 0 => Ok(Self(None)),
884 1 => Ok(Self(Some(items.remove(0)))),
885 n => Err(serde::de::Error::custom(format!(
886 "nested Optional expects a 0- or 1-element array, got {n}"
887 ))),
888 }
889 }
890}
891
892#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
899pub struct Unit;
900
901impl serde::Serialize for Unit {
902 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
903 use serde::ser::SerializeMap;
905 serializer.serialize_map(Some(0))?.end()
906 }
907}
908
909impl<'de> serde::Deserialize<'de> for Unit {
910 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
911 struct UnitVisitor;
913 impl<'de> serde::de::Visitor<'de> for UnitVisitor {
914 type Value = Unit;
915 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
916 f.write_str("the empty object `{}` (Daml Unit)")
917 }
918 fn visit_map<A: serde::de::MapAccess<'de>>(self, mut map: A) -> Result<Unit, A::Error> {
919 while map
920 .next_entry::<serde::de::IgnoredAny, serde::de::IgnoredAny>()?
921 .is_some()
922 {}
923 Ok(Unit)
924 }
925 fn visit_unit<E: serde::de::Error>(self) -> Result<Unit, E> {
926 Ok(Unit)
927 }
928 }
929 deserializer.deserialize_any(UnitVisitor)
930 }
931}