create-sia-app 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +179 -0
- package/package.json +29 -0
- package/template/CLAUDE.md +160 -0
- package/template/README.md +102 -0
- package/template/_gitignore +5 -0
- package/template/biome.json +40 -0
- package/template/index.html +13 -0
- package/template/package.json +30 -0
- package/template/rust/README.md +16 -0
- package/template/rust/sia-sdk-rs/.changeset/added_cancel_function_to_cancel_inflight_packed_uploads.md +6 -0
- package/template/rust/sia-sdk-rs/.changeset/check_if_we_have_enough_hosts_prior_to_encoding_in_upload_slabs.md +16 -0
- package/template/rust/sia-sdk-rs/.changeset/fix_slab_length_in_packed_object.md +5 -0
- package/template/rust/sia-sdk-rs/.changeset/fix_upload_racing_race_conditon.md +13 -0
- package/template/rust/sia-sdk-rs/.changeset/improved_parallelism_of_packed_uploads.md +5 -0
- package/template/rust/sia-sdk-rs/.changeset/progress_callback_will_now_be_called_as_expected_for_packed_uploads.md +5 -0
- package/template/rust/sia-sdk-rs/.github/dependabot.yml +10 -0
- package/template/rust/sia-sdk-rs/.github/workflows/main.yml +36 -0
- package/template/rust/sia-sdk-rs/.github/workflows/prepare-release.yml +34 -0
- package/template/rust/sia-sdk-rs/.github/workflows/release.yml +30 -0
- package/template/rust/sia-sdk-rs/.rustfmt.toml +4 -0
- package/template/rust/sia-sdk-rs/Cargo.lock +4127 -0
- package/template/rust/sia-sdk-rs/Cargo.toml +3 -0
- package/template/rust/sia-sdk-rs/LICENSE +21 -0
- package/template/rust/sia-sdk-rs/README.md +30 -0
- package/template/rust/sia-sdk-rs/indexd/CHANGELOG.md +79 -0
- package/template/rust/sia-sdk-rs/indexd/Cargo.toml +79 -0
- package/template/rust/sia-sdk-rs/indexd/benches/upload.rs +258 -0
- package/template/rust/sia-sdk-rs/indexd/src/app_client.rs +1710 -0
- package/template/rust/sia-sdk-rs/indexd/src/builder.rs +354 -0
- package/template/rust/sia-sdk-rs/indexd/src/download.rs +379 -0
- package/template/rust/sia-sdk-rs/indexd/src/hosts.rs +659 -0
- package/template/rust/sia-sdk-rs/indexd/src/lib.rs +827 -0
- package/template/rust/sia-sdk-rs/indexd/src/mock.rs +162 -0
- package/template/rust/sia-sdk-rs/indexd/src/object_encryption.rs +125 -0
- package/template/rust/sia-sdk-rs/indexd/src/quic.rs +575 -0
- package/template/rust/sia-sdk-rs/indexd/src/rhp4.rs +52 -0
- package/template/rust/sia-sdk-rs/indexd/src/slabs.rs +497 -0
- package/template/rust/sia-sdk-rs/indexd/src/upload.rs +629 -0
- package/template/rust/sia-sdk-rs/indexd/src/wasm_time.rs +41 -0
- package/template/rust/sia-sdk-rs/indexd/src/web_transport.rs +398 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/CHANGELOG.md +76 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/Cargo.toml +47 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/README.md +10 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/example.py +130 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/bin/uniffi-bindgen.rs +3 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/builder.rs +377 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/io.rs +155 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/lib.rs +1039 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/logging.rs +58 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/tls.rs +23 -0
- package/template/rust/sia-sdk-rs/indexd_wasm/Cargo.toml +33 -0
- package/template/rust/sia-sdk-rs/indexd_wasm/src/lib.rs +818 -0
- package/template/rust/sia-sdk-rs/knope.toml +54 -0
- package/template/rust/sia-sdk-rs/sia_derive/CHANGELOG.md +38 -0
- package/template/rust/sia-sdk-rs/sia_derive/Cargo.toml +19 -0
- package/template/rust/sia-sdk-rs/sia_derive/src/lib.rs +278 -0
- package/template/rust/sia-sdk-rs/sia_sdk/CHANGELOG.md +91 -0
- package/template/rust/sia-sdk-rs/sia_sdk/Cargo.toml +59 -0
- package/template/rust/sia-sdk-rs/sia_sdk/benches/merkle_root.rs +12 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/blake2.rs +22 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/consensus.rs +767 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v1.rs +257 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v2.rs +291 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding.rs +26 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async/v2.rs +367 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async.rs +6 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encryption.rs +303 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/erasure_coding.rs +347 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/lib.rs +15 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/macros.rs +435 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/merkle.rs +112 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/merkle.rs +357 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/rpc.rs +1507 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/types.rs +146 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp.rs +7 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/seed.rs +278 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/signing.rs +236 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/common.rs +677 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/currency.rs +450 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/specifier.rs +110 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/spendpolicy.rs +778 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/utils.rs +117 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/v1.rs +1737 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/v2.rs +1726 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/work.rs +59 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types.rs +16 -0
- package/template/scripts/setup-rust.js +29 -0
- package/template/src/App.tsx +13 -0
- package/template/src/components/DevNote.tsx +21 -0
- package/template/src/components/auth/ApproveScreen.tsx +84 -0
- package/template/src/components/auth/AuthFlow.tsx +77 -0
- package/template/src/components/auth/ConnectScreen.tsx +214 -0
- package/template/src/components/auth/LoadingScreen.tsx +8 -0
- package/template/src/components/auth/RecoveryScreen.tsx +182 -0
- package/template/src/components/upload/UploadZone.tsx +314 -0
- package/template/src/index.css +9 -0
- package/template/src/lib/constants.ts +8 -0
- package/template/src/lib/format.ts +35 -0
- package/template/src/lib/hex.ts +13 -0
- package/template/src/lib/sdk.ts +25 -0
- package/template/src/lib/wasm-env.ts +5 -0
- package/template/src/main.tsx +12 -0
- package/template/src/stores/auth.ts +86 -0
- package/template/tsconfig.app.json +31 -0
- package/template/tsconfig.json +7 -0
- package/template/tsconfig.node.json +26 -0
- package/template/vite.config.ts +18 -0
- package/template/wasm/indexd_wasm/indexd_wasm.d.ts +309 -0
- package/template/wasm/indexd_wasm/indexd_wasm.js +1507 -0
- package/template/wasm/indexd_wasm/indexd_wasm_bg.wasm +0 -0
- package/template/wasm/indexd_wasm/package.json +31 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
use super::{Error, Result};
|
|
2
|
+
use std::io::{Read, Write};
|
|
3
|
+
|
|
4
|
+
pub trait V1SiaEncodable {
|
|
5
|
+
fn encode_v1<W: Write>(&self, w: &mut W) -> Result<()>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
pub trait V1SiaDecodable: Sized {
|
|
9
|
+
fn decode_v1<R: Read>(r: &mut R) -> Result<Self>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
impl V1SiaEncodable for u8 {
|
|
13
|
+
fn encode_v1<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
14
|
+
w.write_all(&[*self])?;
|
|
15
|
+
Ok(())
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
impl V1SiaDecodable for u8 {
|
|
20
|
+
fn decode_v1<R: Read>(r: &mut R) -> Result<Self> {
|
|
21
|
+
let mut buf = [0; 1];
|
|
22
|
+
r.read_exact(&mut buf)?;
|
|
23
|
+
Ok(buf[0])
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
impl V1SiaEncodable for bool {
|
|
28
|
+
fn encode_v1<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
29
|
+
(*self as u8).encode_v1(w)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
impl V1SiaDecodable for bool {
|
|
34
|
+
fn decode_v1<R: Read>(r: &mut R) -> Result<Self> {
|
|
35
|
+
let v = u8::decode_v1(r)?;
|
|
36
|
+
match v {
|
|
37
|
+
0 => Ok(false),
|
|
38
|
+
1 => Ok(true),
|
|
39
|
+
_ => Err(Error::InvalidValue("requires 0 or 1".into())),
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
impl<T: V1SiaEncodable> V1SiaEncodable for [T] {
|
|
45
|
+
fn encode_v1<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
46
|
+
self.len().encode_v1(w)?;
|
|
47
|
+
for item in self {
|
|
48
|
+
item.encode_v1(w)?;
|
|
49
|
+
}
|
|
50
|
+
Ok(())
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
impl<T: V1SiaEncodable> V1SiaEncodable for Option<T> {
|
|
55
|
+
fn encode_v1<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
56
|
+
match self {
|
|
57
|
+
Some(v) => {
|
|
58
|
+
true.encode_v1(w)?;
|
|
59
|
+
v.encode_v1(w)
|
|
60
|
+
}
|
|
61
|
+
None => false.encode_v1(w),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
impl<T: V1SiaDecodable> V1SiaDecodable for Option<T> {
|
|
67
|
+
fn decode_v1<R: Read>(r: &mut R) -> Result<Self> {
|
|
68
|
+
let has_value = bool::decode_v1(r)?;
|
|
69
|
+
if has_value {
|
|
70
|
+
Ok(Some(T::decode_v1(r)?))
|
|
71
|
+
} else {
|
|
72
|
+
Ok(None)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
macro_rules! impl_sia_numeric {
|
|
78
|
+
($($t:ty),*) => {
|
|
79
|
+
$(
|
|
80
|
+
impl V1SiaEncodable for $t {
|
|
81
|
+
fn encode_v1<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
82
|
+
w.write_all(&(*self as u64).to_le_bytes())?;
|
|
83
|
+
Ok(())
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
impl V1SiaDecodable for $t {
|
|
88
|
+
fn decode_v1<R: Read>(r: &mut R) -> Result<Self> {
|
|
89
|
+
let mut buf = [0u8; 8];
|
|
90
|
+
r.read_exact(&mut buf)?;
|
|
91
|
+
Ok(u64::from_le_bytes(buf) as Self)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
)*
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
impl_sia_numeric!(u16, u32, usize, i16, i32, i64, u64);
|
|
99
|
+
|
|
100
|
+
impl<T> V1SiaEncodable for Vec<T>
|
|
101
|
+
where
|
|
102
|
+
T: V1SiaEncodable,
|
|
103
|
+
{
|
|
104
|
+
fn encode_v1<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
105
|
+
self.len().encode_v1(w)?;
|
|
106
|
+
for item in self {
|
|
107
|
+
item.encode_v1(w)?;
|
|
108
|
+
}
|
|
109
|
+
Ok(())
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
impl<T> V1SiaDecodable for Vec<T>
|
|
114
|
+
where
|
|
115
|
+
T: V1SiaDecodable,
|
|
116
|
+
{
|
|
117
|
+
fn decode_v1<R: Read>(r: &mut R) -> Result<Self> {
|
|
118
|
+
let mut vec = Vec::new();
|
|
119
|
+
// note: the vec is not pre-allocated
|
|
120
|
+
// to prevent abuse by sending a large len
|
|
121
|
+
for _ in 0..usize::decode_v1(r)? {
|
|
122
|
+
vec.push(T::decode_v1(r)?);
|
|
123
|
+
}
|
|
124
|
+
Ok(vec)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
impl V1SiaEncodable for String {
|
|
129
|
+
fn encode_v1<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
130
|
+
self.as_bytes().encode_v1(w)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
impl V1SiaDecodable for String {
|
|
135
|
+
fn decode_v1<R: Read>(r: &mut R) -> Result<Self> {
|
|
136
|
+
let buf = Vec::<u8>::decode_v1(r)?;
|
|
137
|
+
String::from_utf8(buf).map_err(|e| Error::InvalidValue(e.to_string()))
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
impl<const N: usize> V1SiaEncodable for [u8; N] {
|
|
142
|
+
fn encode_v1<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
143
|
+
w.write_all(self)?;
|
|
144
|
+
Ok(())
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
impl<const N: usize> V1SiaDecodable for [u8; N] {
|
|
149
|
+
fn decode_v1<R: Read>(r: &mut R) -> Result<Self> {
|
|
150
|
+
let mut arr = [0u8; N];
|
|
151
|
+
r.read_exact(&mut arr)?;
|
|
152
|
+
Ok(arr)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#[cfg(test)]
|
|
157
|
+
mod tests {
|
|
158
|
+
use super::*;
|
|
159
|
+
|
|
160
|
+
fn test_roundtrip<T: V1SiaEncodable + V1SiaDecodable + std::fmt::Debug + PartialEq>(
|
|
161
|
+
value: T,
|
|
162
|
+
expected_bytes: Vec<u8>,
|
|
163
|
+
) {
|
|
164
|
+
let mut encoded_bytes = Vec::new();
|
|
165
|
+
value
|
|
166
|
+
.encode_v1(&mut encoded_bytes)
|
|
167
|
+
.unwrap_or_else(|e| panic!("failed to encode: {e:?}"));
|
|
168
|
+
|
|
169
|
+
assert_eq!(
|
|
170
|
+
encoded_bytes, expected_bytes,
|
|
171
|
+
"encoding mismatch for {value:?}"
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
let mut bytes = &expected_bytes[..];
|
|
175
|
+
let decoded =
|
|
176
|
+
T::decode_v1(&mut bytes).unwrap_or_else(|e| panic!("failed to decode: {e:?}"));
|
|
177
|
+
assert_eq!(decoded, value, "decoding mismatch for {value:?}");
|
|
178
|
+
|
|
179
|
+
assert_eq!(bytes.len(), 0, "leftover bytes for {value:?}");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
#[test]
|
|
183
|
+
fn test_numerics() {
|
|
184
|
+
test_roundtrip(1u8, vec![1]);
|
|
185
|
+
test_roundtrip(2u16, vec![2, 0, 0, 0, 0, 0, 0, 0]);
|
|
186
|
+
test_roundtrip(3u32, vec![3, 0, 0, 0, 0, 0, 0, 0]);
|
|
187
|
+
test_roundtrip(4u64, vec![4, 0, 0, 0, 0, 0, 0, 0]);
|
|
188
|
+
test_roundtrip(5usize, vec![5, 0, 0, 0, 0, 0, 0, 0]);
|
|
189
|
+
test_roundtrip(-1i16, vec![255, 255, 255, 255, 255, 255, 255, 255]);
|
|
190
|
+
test_roundtrip(-2i32, vec![254, 255, 255, 255, 255, 255, 255, 255]);
|
|
191
|
+
test_roundtrip(-3i64, vec![253, 255, 255, 255, 255, 255, 255, 255]);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#[test]
|
|
195
|
+
fn test_strings() {
|
|
196
|
+
test_roundtrip(
|
|
197
|
+
"hello".to_string(),
|
|
198
|
+
vec![
|
|
199
|
+
5, 0, 0, 0, 0, 0, 0, 0, // length prefix
|
|
200
|
+
104, 101, 108, 108, 111, // "hello"
|
|
201
|
+
],
|
|
202
|
+
);
|
|
203
|
+
test_roundtrip(
|
|
204
|
+
"".to_string(),
|
|
205
|
+
vec![0, 0, 0, 0, 0, 0, 0, 0], // empty string length
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
#[test]
|
|
210
|
+
fn test_fixed_arrays() {
|
|
211
|
+
test_roundtrip([1u8, 2u8, 3u8], vec![1, 2, 3]);
|
|
212
|
+
test_roundtrip([0u8; 4], vec![0, 0, 0, 0]);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
#[test]
|
|
216
|
+
fn test_vectors() {
|
|
217
|
+
test_roundtrip(
|
|
218
|
+
vec![1u8, 2u8, 3u8],
|
|
219
|
+
vec![
|
|
220
|
+
3, 0, 0, 0, 0, 0, 0, 0, // length prefix
|
|
221
|
+
1, 2, 3, // values
|
|
222
|
+
],
|
|
223
|
+
);
|
|
224
|
+
test_roundtrip(
|
|
225
|
+
vec![100u64, 200u64],
|
|
226
|
+
vec![
|
|
227
|
+
2, 0, 0, 0, 0, 0, 0, 0, // length prefix
|
|
228
|
+
100, 0, 0, 0, 0, 0, 0, 0, // 100u64
|
|
229
|
+
200, 0, 0, 0, 0, 0, 0, 0, // 200u64
|
|
230
|
+
],
|
|
231
|
+
);
|
|
232
|
+
test_roundtrip(
|
|
233
|
+
vec!["a".to_string(), "bc".to_string()],
|
|
234
|
+
vec![
|
|
235
|
+
2, 0, 0, 0, 0, 0, 0, 0, // vector length
|
|
236
|
+
1, 0, 0, 0, 0, 0, 0, 0, // first string length
|
|
237
|
+
97, // "a"
|
|
238
|
+
2, 0, 0, 0, 0, 0, 0, 0, // second string length
|
|
239
|
+
98, 99, // "bc"
|
|
240
|
+
],
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#[test]
|
|
245
|
+
fn test_nested() {
|
|
246
|
+
test_roundtrip(
|
|
247
|
+
vec![vec![1u8, 2u8], vec![3u8, 4u8]],
|
|
248
|
+
vec![
|
|
249
|
+
2, 0, 0, 0, 0, 0, 0, 0, // outer vec length
|
|
250
|
+
2, 0, 0, 0, 0, 0, 0, 0, // first inner vec length
|
|
251
|
+
1, 2, // first inner vec contents
|
|
252
|
+
2, 0, 0, 0, 0, 0, 0, 0, // second inner vec length
|
|
253
|
+
3, 4, // second inner vec contents
|
|
254
|
+
],
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
use chrono::{DateTime, Duration, Utc};
|
|
2
|
+
|
|
3
|
+
use super::{Error, Result};
|
|
4
|
+
use std::io::{Read, Write};
|
|
5
|
+
|
|
6
|
+
pub trait SiaEncodable {
|
|
7
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
pub trait SiaDecodable: Sized {
|
|
11
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
impl SiaEncodable for u8 {
|
|
15
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
16
|
+
w.write_all(&[*self])?;
|
|
17
|
+
Ok(())
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl SiaDecodable for u8 {
|
|
22
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self> {
|
|
23
|
+
let mut buf = [0; 1];
|
|
24
|
+
r.read_exact(&mut buf)?;
|
|
25
|
+
Ok(buf[0])
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
impl SiaEncodable for bool {
|
|
30
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
31
|
+
(*self as u8).encode(w)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
impl SiaDecodable for bool {
|
|
36
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self> {
|
|
37
|
+
let v = u8::decode(r)?;
|
|
38
|
+
match v {
|
|
39
|
+
0 => Ok(false),
|
|
40
|
+
1 => Ok(true),
|
|
41
|
+
_ => Err(Error::InvalidValue("requires 0 or 1".into())),
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
impl SiaEncodable for DateTime<Utc> {
|
|
47
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
48
|
+
self.timestamp().encode(w)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
impl SiaDecodable for DateTime<Utc> {
|
|
53
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self> {
|
|
54
|
+
let timestamp = i64::decode(r)?;
|
|
55
|
+
DateTime::from_timestamp_secs(timestamp)
|
|
56
|
+
.ok_or_else(|| Error::InvalidValue(format!("invalid timestamp: {timestamp}")))
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
impl SiaEncodable for Duration {
|
|
61
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
62
|
+
self.num_nanoseconds()
|
|
63
|
+
.ok_or_else(|| Error::InvalidValue("duration too large".into()))?
|
|
64
|
+
.encode(w)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
impl SiaDecodable for Duration {
|
|
69
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self> {
|
|
70
|
+
let ns = u64::decode(r)?;
|
|
71
|
+
if ns > i64::MAX as u64 {
|
|
72
|
+
return Err(Error::InvalidValue(format!(
|
|
73
|
+
"duration {ns} must be less than {}",
|
|
74
|
+
i64::MAX
|
|
75
|
+
)));
|
|
76
|
+
}
|
|
77
|
+
Ok(Duration::nanoseconds(ns as i64))
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
impl<T: SiaEncodable> SiaEncodable for [T] {
|
|
82
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
83
|
+
self.len().encode(w)?;
|
|
84
|
+
for item in self {
|
|
85
|
+
item.encode(w)?;
|
|
86
|
+
}
|
|
87
|
+
Ok(())
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
impl<T: SiaEncodable> SiaEncodable for Option<T> {
|
|
92
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
93
|
+
match self {
|
|
94
|
+
Some(v) => {
|
|
95
|
+
true.encode(w)?;
|
|
96
|
+
v.encode(w)
|
|
97
|
+
}
|
|
98
|
+
None => false.encode(w),
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
impl<T: SiaDecodable> SiaDecodable for Option<T> {
|
|
104
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self> {
|
|
105
|
+
match bool::decode(r)? {
|
|
106
|
+
true => Ok(Some(T::decode(r)?)),
|
|
107
|
+
false => Ok(None),
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
macro_rules! impl_sia_numeric {
|
|
113
|
+
($($t:ty),*) => {
|
|
114
|
+
$(
|
|
115
|
+
impl SiaEncodable for $t {
|
|
116
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
117
|
+
w.write_all(&(*self as u64).to_le_bytes())?;
|
|
118
|
+
Ok(())
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
impl SiaDecodable for $t {
|
|
123
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self> {
|
|
124
|
+
let mut buf = [0u8; 8];
|
|
125
|
+
r.read_exact(&mut buf)?;
|
|
126
|
+
Ok(u64::from_le_bytes(buf) as Self)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
)*
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
impl_sia_numeric!(u16, u32, usize, i16, i32, i64, u64);
|
|
134
|
+
|
|
135
|
+
impl<T> SiaEncodable for Vec<T>
|
|
136
|
+
where
|
|
137
|
+
T: SiaEncodable,
|
|
138
|
+
{
|
|
139
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
140
|
+
self.len().encode(w)?;
|
|
141
|
+
for item in self {
|
|
142
|
+
item.encode(w)?;
|
|
143
|
+
}
|
|
144
|
+
Ok(())
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
impl<T> SiaDecodable for Vec<T>
|
|
149
|
+
where
|
|
150
|
+
T: SiaDecodable,
|
|
151
|
+
{
|
|
152
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self> {
|
|
153
|
+
let mut vec = Vec::new();
|
|
154
|
+
// note: the vec is not pre-allocated
|
|
155
|
+
// to prevent abuse by sending a large len
|
|
156
|
+
for _ in 0..usize::decode(r)? {
|
|
157
|
+
vec.push(T::decode(r)?);
|
|
158
|
+
}
|
|
159
|
+
Ok(vec)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
impl SiaEncodable for String {
|
|
164
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
165
|
+
self.as_bytes().encode(w)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
impl SiaDecodable for String {
|
|
170
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self> {
|
|
171
|
+
let buf = Vec::<u8>::decode(r)?;
|
|
172
|
+
String::from_utf8(buf).map_err(|e| Error::InvalidValue(e.to_string()))
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
impl<const N: usize> SiaEncodable for [u8; N] {
|
|
177
|
+
fn encode<W: Write>(&self, w: &mut W) -> Result<()> {
|
|
178
|
+
w.write_all(self)?;
|
|
179
|
+
Ok(())
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
impl<const N: usize> SiaDecodable for [u8; N] {
|
|
184
|
+
fn decode<R: Read>(r: &mut R) -> Result<Self> {
|
|
185
|
+
let mut arr = [0u8; N];
|
|
186
|
+
r.read_exact(&mut arr)?;
|
|
187
|
+
Ok(arr)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
#[cfg(test)]
|
|
192
|
+
mod tests {
|
|
193
|
+
use super::*;
|
|
194
|
+
|
|
195
|
+
fn test_roundtrip<T: SiaEncodable + SiaDecodable + std::fmt::Debug + PartialEq>(
|
|
196
|
+
value: T,
|
|
197
|
+
expected_bytes: Vec<u8>,
|
|
198
|
+
) {
|
|
199
|
+
let mut encoded_bytes = Vec::new();
|
|
200
|
+
value
|
|
201
|
+
.encode(&mut encoded_bytes)
|
|
202
|
+
.unwrap_or_else(|e| panic!("failed to encode: {e:?}"));
|
|
203
|
+
|
|
204
|
+
assert_eq!(
|
|
205
|
+
encoded_bytes, expected_bytes,
|
|
206
|
+
"encoding mismatch for {value:?}"
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
let mut bytes = &expected_bytes[..];
|
|
210
|
+
let decoded = T::decode(&mut bytes).unwrap_or_else(|e| panic!("failed to decode: {e:?}"));
|
|
211
|
+
assert_eq!(decoded, value, "decoding mismatch for {value:?}");
|
|
212
|
+
|
|
213
|
+
assert_eq!(bytes.len(), 0, "leftover bytes for {value:?}");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
#[test]
|
|
217
|
+
fn test_numerics() {
|
|
218
|
+
test_roundtrip(1u8, vec![1]);
|
|
219
|
+
test_roundtrip(2u16, vec![2, 0, 0, 0, 0, 0, 0, 0]);
|
|
220
|
+
test_roundtrip(3u32, vec![3, 0, 0, 0, 0, 0, 0, 0]);
|
|
221
|
+
test_roundtrip(4u64, vec![4, 0, 0, 0, 0, 0, 0, 0]);
|
|
222
|
+
test_roundtrip(5usize, vec![5, 0, 0, 0, 0, 0, 0, 0]);
|
|
223
|
+
test_roundtrip(-1i16, vec![255, 255, 255, 255, 255, 255, 255, 255]);
|
|
224
|
+
test_roundtrip(-2i32, vec![254, 255, 255, 255, 255, 255, 255, 255]);
|
|
225
|
+
test_roundtrip(-3i64, vec![253, 255, 255, 255, 255, 255, 255, 255]);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
#[test]
|
|
229
|
+
fn test_strings() {
|
|
230
|
+
test_roundtrip(
|
|
231
|
+
"hello".to_string(),
|
|
232
|
+
vec![
|
|
233
|
+
5, 0, 0, 0, 0, 0, 0, 0, // length prefix
|
|
234
|
+
104, 101, 108, 108, 111, // "hello"
|
|
235
|
+
],
|
|
236
|
+
);
|
|
237
|
+
test_roundtrip(
|
|
238
|
+
"".to_string(),
|
|
239
|
+
vec![0, 0, 0, 0, 0, 0, 0, 0], // empty string length
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#[test]
|
|
244
|
+
fn test_fixed_arrays() {
|
|
245
|
+
test_roundtrip([1u8, 2u8, 3u8], vec![1, 2, 3]);
|
|
246
|
+
test_roundtrip([0u8; 4], vec![0, 0, 0, 0]);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
#[test]
|
|
250
|
+
fn test_vectors() {
|
|
251
|
+
test_roundtrip(
|
|
252
|
+
vec![1u8, 2u8, 3u8],
|
|
253
|
+
vec![
|
|
254
|
+
3, 0, 0, 0, 0, 0, 0, 0, // length prefix
|
|
255
|
+
1, 2, 3, // values
|
|
256
|
+
],
|
|
257
|
+
);
|
|
258
|
+
test_roundtrip(
|
|
259
|
+
vec![100u64, 200u64],
|
|
260
|
+
vec![
|
|
261
|
+
2, 0, 0, 0, 0, 0, 0, 0, // length prefix
|
|
262
|
+
100, 0, 0, 0, 0, 0, 0, 0, // 100u64
|
|
263
|
+
200, 0, 0, 0, 0, 0, 0, 0, // 200u64
|
|
264
|
+
],
|
|
265
|
+
);
|
|
266
|
+
test_roundtrip(
|
|
267
|
+
vec!["a".to_string(), "bc".to_string()],
|
|
268
|
+
vec![
|
|
269
|
+
2, 0, 0, 0, 0, 0, 0, 0, // vector length
|
|
270
|
+
1, 0, 0, 0, 0, 0, 0, 0, // first string length
|
|
271
|
+
97, // "a"
|
|
272
|
+
2, 0, 0, 0, 0, 0, 0, 0, // second string length
|
|
273
|
+
98, 99, // "bc"
|
|
274
|
+
],
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
#[test]
|
|
279
|
+
fn test_nested() {
|
|
280
|
+
test_roundtrip(
|
|
281
|
+
vec![vec![1u8, 2u8], vec![3u8, 4u8]],
|
|
282
|
+
vec![
|
|
283
|
+
2, 0, 0, 0, 0, 0, 0, 0, // outer vec length
|
|
284
|
+
2, 0, 0, 0, 0, 0, 0, 0, // first inner vec length
|
|
285
|
+
1, 2, // first inner vec contents
|
|
286
|
+
2, 0, 0, 0, 0, 0, 0, 0, // second inner vec length
|
|
287
|
+
3, 4, // second inner vec contents
|
|
288
|
+
],
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
use std::io;
|
|
2
|
+
|
|
3
|
+
use thiserror::Error;
|
|
4
|
+
|
|
5
|
+
mod v1;
|
|
6
|
+
mod v2;
|
|
7
|
+
|
|
8
|
+
#[derive(Debug, Error)]
|
|
9
|
+
pub enum Error {
|
|
10
|
+
#[error("IO error: {0}")]
|
|
11
|
+
Io(#[from] io::Error),
|
|
12
|
+
#[error("Invalid length")]
|
|
13
|
+
InvalidLength(usize),
|
|
14
|
+
#[error("Invalid value: {0}")]
|
|
15
|
+
InvalidValue(String),
|
|
16
|
+
#[error("Custom error: {0}")]
|
|
17
|
+
Custom(String),
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
pub type Result<T> = std::result::Result<T, Error>;
|
|
21
|
+
|
|
22
|
+
pub use sia_derive::{SiaDecode, SiaEncode};
|
|
23
|
+
pub use v2::{SiaDecodable, SiaEncodable};
|
|
24
|
+
|
|
25
|
+
pub use sia_derive::{V1SiaDecode, V1SiaEncode};
|
|
26
|
+
pub use v1::{V1SiaDecodable, V1SiaEncodable};
|