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.
Files changed (112) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +179 -0
  3. package/package.json +29 -0
  4. package/template/CLAUDE.md +160 -0
  5. package/template/README.md +102 -0
  6. package/template/_gitignore +5 -0
  7. package/template/biome.json +40 -0
  8. package/template/index.html +13 -0
  9. package/template/package.json +30 -0
  10. package/template/rust/README.md +16 -0
  11. package/template/rust/sia-sdk-rs/.changeset/added_cancel_function_to_cancel_inflight_packed_uploads.md +6 -0
  12. package/template/rust/sia-sdk-rs/.changeset/check_if_we_have_enough_hosts_prior_to_encoding_in_upload_slabs.md +16 -0
  13. package/template/rust/sia-sdk-rs/.changeset/fix_slab_length_in_packed_object.md +5 -0
  14. package/template/rust/sia-sdk-rs/.changeset/fix_upload_racing_race_conditon.md +13 -0
  15. package/template/rust/sia-sdk-rs/.changeset/improved_parallelism_of_packed_uploads.md +5 -0
  16. package/template/rust/sia-sdk-rs/.changeset/progress_callback_will_now_be_called_as_expected_for_packed_uploads.md +5 -0
  17. package/template/rust/sia-sdk-rs/.github/dependabot.yml +10 -0
  18. package/template/rust/sia-sdk-rs/.github/workflows/main.yml +36 -0
  19. package/template/rust/sia-sdk-rs/.github/workflows/prepare-release.yml +34 -0
  20. package/template/rust/sia-sdk-rs/.github/workflows/release.yml +30 -0
  21. package/template/rust/sia-sdk-rs/.rustfmt.toml +4 -0
  22. package/template/rust/sia-sdk-rs/Cargo.lock +4127 -0
  23. package/template/rust/sia-sdk-rs/Cargo.toml +3 -0
  24. package/template/rust/sia-sdk-rs/LICENSE +21 -0
  25. package/template/rust/sia-sdk-rs/README.md +30 -0
  26. package/template/rust/sia-sdk-rs/indexd/CHANGELOG.md +79 -0
  27. package/template/rust/sia-sdk-rs/indexd/Cargo.toml +79 -0
  28. package/template/rust/sia-sdk-rs/indexd/benches/upload.rs +258 -0
  29. package/template/rust/sia-sdk-rs/indexd/src/app_client.rs +1710 -0
  30. package/template/rust/sia-sdk-rs/indexd/src/builder.rs +354 -0
  31. package/template/rust/sia-sdk-rs/indexd/src/download.rs +379 -0
  32. package/template/rust/sia-sdk-rs/indexd/src/hosts.rs +659 -0
  33. package/template/rust/sia-sdk-rs/indexd/src/lib.rs +827 -0
  34. package/template/rust/sia-sdk-rs/indexd/src/mock.rs +162 -0
  35. package/template/rust/sia-sdk-rs/indexd/src/object_encryption.rs +125 -0
  36. package/template/rust/sia-sdk-rs/indexd/src/quic.rs +575 -0
  37. package/template/rust/sia-sdk-rs/indexd/src/rhp4.rs +52 -0
  38. package/template/rust/sia-sdk-rs/indexd/src/slabs.rs +497 -0
  39. package/template/rust/sia-sdk-rs/indexd/src/upload.rs +629 -0
  40. package/template/rust/sia-sdk-rs/indexd/src/wasm_time.rs +41 -0
  41. package/template/rust/sia-sdk-rs/indexd/src/web_transport.rs +398 -0
  42. package/template/rust/sia-sdk-rs/indexd_ffi/CHANGELOG.md +76 -0
  43. package/template/rust/sia-sdk-rs/indexd_ffi/Cargo.toml +47 -0
  44. package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/README.md +10 -0
  45. package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/example.py +130 -0
  46. package/template/rust/sia-sdk-rs/indexd_ffi/src/bin/uniffi-bindgen.rs +3 -0
  47. package/template/rust/sia-sdk-rs/indexd_ffi/src/builder.rs +377 -0
  48. package/template/rust/sia-sdk-rs/indexd_ffi/src/io.rs +155 -0
  49. package/template/rust/sia-sdk-rs/indexd_ffi/src/lib.rs +1039 -0
  50. package/template/rust/sia-sdk-rs/indexd_ffi/src/logging.rs +58 -0
  51. package/template/rust/sia-sdk-rs/indexd_ffi/src/tls.rs +23 -0
  52. package/template/rust/sia-sdk-rs/indexd_wasm/Cargo.toml +33 -0
  53. package/template/rust/sia-sdk-rs/indexd_wasm/src/lib.rs +818 -0
  54. package/template/rust/sia-sdk-rs/knope.toml +54 -0
  55. package/template/rust/sia-sdk-rs/sia_derive/CHANGELOG.md +38 -0
  56. package/template/rust/sia-sdk-rs/sia_derive/Cargo.toml +19 -0
  57. package/template/rust/sia-sdk-rs/sia_derive/src/lib.rs +278 -0
  58. package/template/rust/sia-sdk-rs/sia_sdk/CHANGELOG.md +91 -0
  59. package/template/rust/sia-sdk-rs/sia_sdk/Cargo.toml +59 -0
  60. package/template/rust/sia-sdk-rs/sia_sdk/benches/merkle_root.rs +12 -0
  61. package/template/rust/sia-sdk-rs/sia_sdk/src/blake2.rs +22 -0
  62. package/template/rust/sia-sdk-rs/sia_sdk/src/consensus.rs +767 -0
  63. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v1.rs +257 -0
  64. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v2.rs +291 -0
  65. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding.rs +26 -0
  66. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async/v2.rs +367 -0
  67. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async.rs +6 -0
  68. package/template/rust/sia-sdk-rs/sia_sdk/src/encryption.rs +303 -0
  69. package/template/rust/sia-sdk-rs/sia_sdk/src/erasure_coding.rs +347 -0
  70. package/template/rust/sia-sdk-rs/sia_sdk/src/lib.rs +15 -0
  71. package/template/rust/sia-sdk-rs/sia_sdk/src/macros.rs +435 -0
  72. package/template/rust/sia-sdk-rs/sia_sdk/src/merkle.rs +112 -0
  73. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/merkle.rs +357 -0
  74. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/rpc.rs +1507 -0
  75. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/types.rs +146 -0
  76. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp.rs +7 -0
  77. package/template/rust/sia-sdk-rs/sia_sdk/src/seed.rs +278 -0
  78. package/template/rust/sia-sdk-rs/sia_sdk/src/signing.rs +236 -0
  79. package/template/rust/sia-sdk-rs/sia_sdk/src/types/common.rs +677 -0
  80. package/template/rust/sia-sdk-rs/sia_sdk/src/types/currency.rs +450 -0
  81. package/template/rust/sia-sdk-rs/sia_sdk/src/types/specifier.rs +110 -0
  82. package/template/rust/sia-sdk-rs/sia_sdk/src/types/spendpolicy.rs +778 -0
  83. package/template/rust/sia-sdk-rs/sia_sdk/src/types/utils.rs +117 -0
  84. package/template/rust/sia-sdk-rs/sia_sdk/src/types/v1.rs +1737 -0
  85. package/template/rust/sia-sdk-rs/sia_sdk/src/types/v2.rs +1726 -0
  86. package/template/rust/sia-sdk-rs/sia_sdk/src/types/work.rs +59 -0
  87. package/template/rust/sia-sdk-rs/sia_sdk/src/types.rs +16 -0
  88. package/template/scripts/setup-rust.js +29 -0
  89. package/template/src/App.tsx +13 -0
  90. package/template/src/components/DevNote.tsx +21 -0
  91. package/template/src/components/auth/ApproveScreen.tsx +84 -0
  92. package/template/src/components/auth/AuthFlow.tsx +77 -0
  93. package/template/src/components/auth/ConnectScreen.tsx +214 -0
  94. package/template/src/components/auth/LoadingScreen.tsx +8 -0
  95. package/template/src/components/auth/RecoveryScreen.tsx +182 -0
  96. package/template/src/components/upload/UploadZone.tsx +314 -0
  97. package/template/src/index.css +9 -0
  98. package/template/src/lib/constants.ts +8 -0
  99. package/template/src/lib/format.ts +35 -0
  100. package/template/src/lib/hex.ts +13 -0
  101. package/template/src/lib/sdk.ts +25 -0
  102. package/template/src/lib/wasm-env.ts +5 -0
  103. package/template/src/main.tsx +12 -0
  104. package/template/src/stores/auth.ts +86 -0
  105. package/template/tsconfig.app.json +31 -0
  106. package/template/tsconfig.json +7 -0
  107. package/template/tsconfig.node.json +26 -0
  108. package/template/vite.config.ts +18 -0
  109. package/template/wasm/indexd_wasm/indexd_wasm.d.ts +309 -0
  110. package/template/wasm/indexd_wasm/indexd_wasm.js +1507 -0
  111. package/template/wasm/indexd_wasm/indexd_wasm_bg.wasm +0 -0
  112. 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};