daml_lf/payload.rs
1use crate::element::DamlPackage;
2use crate::error::{DamlLfError, DamlLfResult};
3use crate::lf_protobuf::com::daml::daml_lf::archive_payload::Sum;
4use crate::lf_protobuf::com::daml::daml_lf::ArchivePayload;
5use crate::lf_protobuf::com::daml::daml_lf_1;
6use crate::lf_protobuf::com::daml::daml_lf_1::module::Name;
7use crate::{convert, LanguageV1MinorVersion, LanguageVersion};
8use bytes::Bytes;
9use itertools::Itertools;
10use prost::Message;
11use std::convert::TryFrom;
12
13/// A `Daml LF` archive payload (aka "package").
14///
15/// A `Daml LF` archive payload contains a `package` and a `language_version`.
16#[derive(Debug, Clone)]
17pub struct DamlLfArchivePayload {
18 pub language_version: LanguageVersion,
19 pub package: DamlLfPackage,
20}
21
22impl DamlLfArchivePayload {
23 /// Create a `DamlLfArchivePayload` from an existing [`DamlLfPackage`] and `language_version`.
24 ///
25 /// [`DamlLfPackage`]: enum.DamlLfPackage.html
26 pub const fn new(language_version: LanguageVersion, package: DamlLfPackage) -> Self {
27 Self {
28 language_version,
29 package,
30 }
31 }
32
33 /// Create a `DamlLfArchivePayload` from a serialized protobuf byte buffer.
34 ///
35 /// This method is suitable for use with the bytes returned by the [`payload()`] method of [`DamlPackage`] which is
36 /// returned by the [`get_package`] and [`get_package_sync`] methods.
37 ///
38 /// # Errors
39 ///
40 /// If the `payload_buffer` cannot be deserialized into a `DamlLfArchivePayload` then
41 /// [`DamlLfParseError`] will be returned.
42 ///
43 /// If the deserialized `DamlLfArchivePayload` is not of a known version then [`UnknownVersion`]
44 /// will be returned.
45 ///
46 /// Archives of `Daml LF` `v0` are not supported and will result in a [`UnsupportedVersion`]
47 /// being returned.
48 ///
49 /// ```no_run
50 /// # use daml_lf::DamlLfResult;
51 /// # use daml_lf::DamlLfArchivePayload;
52 /// # fn main() -> DamlLfResult<()> {
53 /// let buffer = Vec::<u8>::new();
54 /// let payload = DamlLfArchivePayload::from_bytes(buffer)?;
55 /// assert_eq!(true, payload.contains_module("PingPong"));
56 /// # Ok(())
57 /// # }
58 /// ```
59 /// [`get_package`]:
60 /// ../daml-grpc/service/daml_package_service/struct.DamlPackageService.html#method.get_package
61 /// [`get_package_sync`]:
62 /// ../daml-grpc/service/daml_package_service/struct.DamlPackageService.html#method.get_package_sync
63 /// [`payload()`]: https://docs.rs/daml-grpc/0.2.2/daml_grpc/data/package/struct.DamlPackage.html#method.payload
64 /// [`DamlPackage`]: https://docs.rs/daml-grpc/0.2.2/daml_grpc/data/package/struct.DamlPackage.html
65 /// [`UnsupportedVersion`]: DamlLfError::UnsupportedVersion
66 /// [`DamlLfParseError`]: DamlLfError::DamlLfParseError
67 /// [`UnknownVersion`]: DamlLfError::UnknownVersion
68 pub fn from_bytes(payload_buffer: impl Into<Bytes>) -> DamlLfResult<Self> {
69 let payload: ArchivePayload = ArchivePayload::decode(payload_buffer.into())?;
70 match payload.sum {
71 Some(Sum::DamlLf1(p)) => Ok(Self::new(
72 LanguageVersion::new_v1(LanguageV1MinorVersion::try_from(payload.minor.as_str())?),
73 DamlLfPackage::V1(p),
74 )),
75 _ => Err(DamlLfError::new_unknown_version("none")),
76 }
77 }
78
79 /// Create a [`DamlArchive`] from this [`DamlLfArchivePayload`] and apply it to `f`.
80 ///
81 /// See [`DarFile::apply`] for details.
82 ///
83 /// [`DamlArchive`]: crate::element::DamlArchive
84 /// [`DarFile::apply`]: crate::dar::DarFile::apply
85 pub fn apply<R, F>(self, f: F) -> DamlLfResult<R>
86 where
87 F: FnOnce(&DamlPackage<'_>) -> R,
88 {
89 convert::apply_payload(self, f)
90 }
91
92 /// Returns true if the `package` within this `DamlLfArchivePayload` contains `module`, false otherwise.
93 ///
94 /// The supplied `module` name is assumed to be in `DottedName` format, i.e. `TopModule.SubModule.Module`.
95 ///
96 /// ```no_run
97 /// # use daml_lf::DamlLfResult;
98 /// # use daml_lf::DamlLfArchivePayload;
99 /// # fn main() -> DamlLfResult<()> {
100 /// let buffer = Vec::<u8>::new();
101 /// let payload = DamlLfArchivePayload::from_bytes(buffer)?;
102 /// assert_eq!(true, payload.contains_module("PingPong"));
103 /// # Ok(())
104 /// # }
105 /// ```
106 pub fn contains_module(&self, module: &str) -> bool {
107 match &self.package {
108 DamlLfPackage::V1(package) => package.modules.iter().any(|m| match &m.name {
109 Some(name) => self.decode_dotted_name(name) == module,
110 _ => false,
111 }),
112 }
113 }
114
115 /// Returns a list of all module names with the `package` contained within this `DamlLfArchivePayload`.
116 ///
117 /// The returned module names are strings in `DottedName` format, i.e. `TopModule.SubModule.Module`.
118 ///
119 /// ```no_run
120 /// # use daml_lf::DamlLfResult;
121 /// # use daml_lf::DamlLfArchivePayload;
122 /// # fn main() -> DamlLfResult<()> {
123 /// let buffer = Vec::<u8>::new();
124 /// let payload = DamlLfArchivePayload::from_bytes(buffer)?;
125 /// assert_eq!(vec!["PingPong", "Module1.Module2"], payload.list_modules());
126 /// # Ok(())
127 /// # }
128 /// ```
129 pub fn list_modules(&self) -> Vec<String> {
130 match &self.package {
131 DamlLfPackage::V1(package) =>
132 package.modules.iter().filter_map(|m| m.name.as_ref().map(|dn| self.decode_dotted_name(dn))).collect(),
133 }
134 }
135
136 /// The `language_version` version of this `payload`.
137 pub const fn language_version(&self) -> &LanguageVersion {
138 &self.language_version
139 }
140
141 /// The package embedded in this `payload`.
142 pub const fn package(&self) -> &DamlLfPackage {
143 &self.package
144 }
145
146 fn decode_dotted_name(&self, name: &Name) -> String {
147 match &self.package {
148 DamlLfPackage::V1(package) => match name {
149 Name::NameInternedDname(i) => package
150 .interned_dotted_names
151 .get(*i as usize)
152 .map(|dn| {
153 dn.segments_interned_str
154 .iter()
155 .map(|&i| package.interned_strings.get(i as usize).expect("Package.interned_strings"))
156 .join(".")
157 })
158 .expect("Package.interned_dotted_names"),
159 Name::NameDname(dn) => dn.segments.join("."),
160 },
161 }
162 }
163}
164
165/// The supported `Daml LF` package formats.
166#[derive(Debug, Clone)]
167pub enum DamlLfPackage {
168 V1(daml_lf_1::Package),
169}