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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
use crate::element::DamlPackage;
use crate::lf_protobuf::com::daml::daml_lf::Archive;
use crate::DamlLfResult;
use crate::{convert, DamlLfArchivePayload};
use bytes::Bytes;
use prost::Message;
use std::ffi::OsStr;
use std::fs::File;
use std::io::Read;
use std::path::Path;
/// The default name for an unnamed archive.
pub const DEFAULT_ARCHIVE_NAME: &str = "Unnamed";
/// A `Daml LF` archive (aka a `dalf` file).
///
/// A `DamlLfArchive` contains a `name`, a `payload` (aka "package"), a `hash` (aka "package id") of that `payload` for
/// a given `hash_function`.
#[derive(Debug, Clone)]
pub struct DamlLfArchive {
pub name: String,
pub payload: DamlLfArchivePayload,
pub hash_function: DamlLfHashFunction,
pub hash: String,
}
impl DamlLfArchive {
/// Create an archive from an existing `payload`, `hash_function` and `hash`.
///
/// Note that this method does not validate that the supplied `hash` is valid for the supplied `payload` and
/// `hash_function` and thus could create an invalid archive.
pub fn new(
name: impl Into<String>,
payload: impl Into<DamlLfArchivePayload>,
hash_function: impl Into<DamlLfHashFunction>,
hash: impl Into<String>,
) -> Self {
Self {
name: name.into(),
payload: payload.into(),
hash_function: hash_function.into(),
hash: hash.into(),
}
}
/// Deserialize an archive from the protobuf binary representation with a default name.
///
/// Deserialize the supplied protobuf `bytes` into a `DamlLfArchive`. The embedded `payload` (bytes) will also
/// be deserialized into a [`DamlLfArchivePayload`].
///
/// # Errors
///
/// If the provided bytes cannot be deserialized into an archive (or the embedded `payload` cannot be deserialized
/// into a [`DamlLfArchivePayload`]) then [`DamlLfParseError`] will be returned.
///
/// If the embedded `payload` is not of a known version then [`UnknownVersion`] will be returned.
///
/// Archives of `Daml LF` `v0` are not supported and will result in a [`UnsupportedVersion`] being returned.
///
/// # Examples
///
/// ```no_run
/// # use daml_lf::{DamlLfArchive, DamlLfHashFunction};
/// # use daml_lf::DamlLfResult;
/// # fn main() -> DamlLfResult<()> {
/// let buffer = Vec::<u8>::new();
/// let archive = DamlLfArchive::from_bytes(buffer)?;
/// assert_eq!(&DamlLfHashFunction::Sha256, archive.hash_function());
/// # Ok(())
/// # }
/// ```
/// [`DamlLfParseError`]: crate::DamlLfError::DamlLfParseError
/// [`UnknownVersion`]: crate::DamlLfError::UnknownVersion
/// [`UnsupportedVersion`]: crate::DamlLfError::UnsupportedVersion
/// [`DamlLfArchivePayload`]: DamlLfArchivePayload
pub fn from_bytes(bytes: impl Into<Bytes>) -> DamlLfResult<Self> {
Self::from_bytes_named(DEFAULT_ARCHIVE_NAME, bytes)
}
/// Deserialize a named archive from the protobuf binary representation.
///
/// Deserialize the supplied protobuf `bytes` into a `DamlLfArchive`. The embedded `payload` (bytes) will also
/// be deserialized into a [`DamlLfArchivePayload`].
///
/// # Errors
///
/// If the provided bytes cannot be deserialized into an archive (or the embedded `payload` cannot be deserialized
/// into a [`DamlLfArchivePayload`]) then [`DamlLfParseError`] will be returned.
///
/// If the embedded `payload` is not of a known version then [`UnknownVersion`] will be returned.
///
/// Archives of `Daml LF` `v0` are not supported and will result in a [`UnsupportedVersion`] being returned.
///
/// # Examples
///
/// ```no_run
/// # use daml_lf::{DamlLfArchive, DamlLfHashFunction};
/// # use daml_lf::DamlLfResult;
/// # fn main() -> DamlLfResult<()> {
/// let buffer = Vec::<u8>::new();
/// let archive = DamlLfArchive::from_bytes_named("foo", buffer)?;
/// assert_eq!(&DamlLfHashFunction::Sha256, archive.hash_function());
/// assert_eq!("foo", archive.name());
/// # Ok(())
/// # }
/// ```
/// [`DamlLfParseError`]: crate::DamlLfError::DamlLfParseError
/// [`UnknownVersion`]: crate::DamlLfError::UnknownVersion
/// [`UnsupportedVersion`]: crate::DamlLfError::UnsupportedVersion
/// [`DamlLfArchivePayload`]: DamlLfArchivePayload
pub fn from_bytes_named(name: impl Into<String>, bytes: impl Into<Bytes>) -> DamlLfResult<Self> {
let archive: Archive = Archive::decode(bytes.into())?;
let payload = DamlLfArchivePayload::from_bytes(archive.payload)?;
let archive_name = name.into();
let sanitized_name = archive_name.rfind(&archive.hash).map_or(&archive_name[..], |i| &archive_name[..i - 1]);
Ok(Self::new(sanitized_name, payload, DamlLfHashFunction::Sha256, archive.hash))
}
/// Read and parse an archive from a `dalf` file.
///
/// # Errors
///
/// If the provided file cannot be read an [`IOError`] will be returned which contains the underlying IO error.
///
/// If the contents of the file cannot be deserialized into an archive (or the embedded `payload` cannot be
/// deserialized into a [`DamlLfArchivePayload`]) then [`DamlLfParseError`] will be returned.
///
/// If the embedded `payload` is not of a known version then [`UnknownVersion`] will be returned.
///
/// Archives of `Daml LF` `v0` are not supported and will result in a [`UnsupportedVersion`] being returned.
///
/// # Examples
///
/// ```no_run
/// # use daml_lf::{DamlLfArchive, DamlLfHashFunction};
/// # use daml_lf::DamlLfResult;
/// # fn main() -> DamlLfResult<()> {
/// let archive = DamlLfArchive::from_file("Example.dalf")?;
/// assert_eq!(&DamlLfHashFunction::Sha256, archive.hash_function());
/// assert_eq!("Example", archive.name());
/// # Ok(())
/// # }
/// ```
/// [`IOError`]: crate::DamlLfError::IoError
/// [`DamlLfParseError`]: crate::DamlLfError::DamlLfParseError
/// [`UnknownVersion`]: crate::DamlLfError::UnknownVersion
/// [`UnsupportedVersion`]: crate::DamlLfError::UnsupportedVersion
/// [`DamlLfArchivePayload`]: DamlLfArchivePayload
pub fn from_file(dalf_path: impl AsRef<Path>) -> DamlLfResult<Self> {
let mut buffer = Vec::new();
let mut dalf_file = File::open(dalf_path.as_ref())?;
dalf_file.read_to_end(&mut buffer)?;
let archive_name_stem = dalf_path.as_ref().file_stem().and_then(OsStr::to_str).unwrap_or(DEFAULT_ARCHIVE_NAME);
Self::from_bytes_named(archive_name_stem, buffer)
}
/// Create a [`DamlArchive`] from a [`DamlLfArchive`] and apply it to `f`.
///
/// See [`DarFile::apply`] for details.
///
/// [`DamlArchive`]: crate::element::DamlArchive
/// [`DarFile::apply`]: crate::dar::DarFile::apply
pub fn apply<R, F>(&self, f: F) -> DamlLfResult<R>
where
F: FnOnce(&DamlPackage<'_>) -> R,
{
convert::apply_dalf(self, f)
}
/// The name of this archive.
pub fn name(&self) -> &str {
&self.name
}
/// The payload (aka "package") contained within this archive.
pub const fn payload(&self) -> &DamlLfArchivePayload {
&self.payload
}
/// The hashing function used to generate this archives `hash`.
pub const fn hash_function(&self) -> &DamlLfHashFunction {
&self.hash_function
}
/// The hash of this archive (aka "package id").
pub fn hash(&self) -> &str {
&self.hash
}
}
/// The hash function used to compute
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum DamlLfHashFunction {
Sha256,
}