logo
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::element::daml_package::DamlPackage;
use crate::element::visitor::{DamlElementVisitor, DamlVisitableElement};
use crate::element::{serialize, DamlData, DamlTyCon, DamlTyConName};
#[cfg(feature = "full")]
use crate::element::{DamlDefValue, DamlValueName};
use bounded_static::ToStatic;
use itertools::Itertools;
use serde::Serialize;
use std::borrow::Cow;
use std::collections::HashMap;

/// A Daml Archive.
#[derive(Debug, Serialize, Clone, Default, ToStatic)]
pub struct DamlArchive<'a> {
    name: Cow<'a, str>,
    main_package_id: Cow<'a, str>,
    #[serde(serialize_with = "serialize::serialize_map")]
    packages: HashMap<Cow<'a, str>, DamlPackage<'a>>,
}

impl<'a> DamlArchive<'a> {
    ///
    pub const fn new(
        name: Cow<'a, str>,
        main_package_id: Cow<'a, str>,
        packages: HashMap<Cow<'a, str>, DamlPackage<'a>>,
    ) -> Self {
        Self {
            name,
            main_package_id,
            packages,
        }
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    /// Return the package id of the main `DamlPackage` contained in this `DamlArchive`.
    pub fn main_package_id(&self) -> &str {
        &self.main_package_id
    }

    /// Return an Iterator of the [`DamlPackage`] in this [`DamlArchive`].
    pub fn packages(&self) -> impl Iterator<Item = &DamlPackage<'_>> {
        self.packages.values()
    }

    /// Return the first [`DamlPackage`] in this [`DamlArchive`] which has the given `name` or `None` if no such
    /// package exists.
    pub fn package_by_name(&self, name: &str) -> Option<&DamlPackage<'_>> {
        self.packages.values().find(|p| p.name() == name)
    }

    /// Return the main [`DamlPackage`] in this [`DamlArchive`] or `None` if no such package exists.
    pub fn main_package(&self) -> Option<&DamlPackage<'_>> {
        self.packages.get(&self.main_package_id)
    }

    /// Retrieve a `DamlData` contained within this `DamlArchive` referred to by the supplied `DamlTyCon` or `None` if
    /// not such data item exists.
    ///
    /// DOCME
    pub fn data_by_tycon<'b>(&'a self, tycon: &'b DamlTyCon<'_>) -> Option<&'a DamlData<'a>> {
        self.data_by_tycon_name(tycon.tycon())
    }

    /// Retrieve a `DamlData` contained within this `DamlArchive` referred to by the supplied `DamlTyConName` or `None`
    /// if not such data item exists.
    ///
    /// DOCME
    pub fn data_by_tycon_name<'b>(&'a self, tycon_name: &'b DamlTyConName<'_>) -> Option<&'a DamlData<'a>> {
        let (package_id, module_path, data_name) = tycon_name.reference_parts();
        self.data(package_id, module_path, data_name)
    }

    /// Retrieve a `DamlData` contained within this `DamlArchive` referred to by the supplied package id, module path &
    /// name or `None` if not such data item exists.
    ///
    /// DOCME
    pub fn data<P, M, D>(&'a self, package_id: P, module_path: &[M], data_name: D) -> Option<&'a DamlData<'a>>
    where
        P: AsRef<str>,
        M: AsRef<str>,
        D: AsRef<str>,
    {
        self.packages
            .get(package_id.as_ref())?
            .root_module()
            .child_module_path(module_path)?
            .data_type(data_name.as_ref())
    }

    /// Retrieve a `DamlDefValue` for a given `DamlValueName` or `None` if no such value exists in this `DamlArchive`.
    ///
    /// DOCME
    #[cfg(feature = "full")]
    pub fn value_by_name<'b>(&'a self, name: &'b DamlValueName<'_>) -> Option<&'a DamlDefValue<'a>> {
        let (package_id, module_path, name) = name.reference_parts();
        self.value(package_id, module_path, name)
    }

    /// Retrieve a `DamlDefValue` for the supplied package id, module path & name or `None` if no such value exists in
    /// this `DamlArchive`.
    ///
    /// DOCME
    #[cfg(feature = "full")]
    pub fn value<P, M, D>(&'a self, package_id: P, module_path: &[M], name: D) -> Option<&'a DamlDefValue<'a>>
    where
        P: AsRef<str>,
        M: AsRef<str>,
        D: AsRef<str>,
    {
        self.packages.get(package_id.as_ref())?.root_module().child_module_path(module_path)?.value(name.as_ref())
    }
}

impl<'a> DamlVisitableElement<'a> for DamlArchive<'a> {
    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
        visitor.pre_visit_archive(self);
        if visitor.sort_elements() {
            self.packages.values().sorted_by_key(|p| p.name()).for_each(|package| package.accept(visitor));
        } else {
            self.packages.values().for_each(|package| package.accept(visitor));
        }
        visitor.post_visit_archive(self);
    }
}