1#![cfg_attr(feature = "derive", doc = "\n\n")]
7#![cfg_attr(feature = "derive", doc = include_str!("../docs/derive_macros.md"))]
8
9#[cfg(feature = "derive")]
10pub use klvm_derive::*;
11
12mod error;
13mod from_klvm;
14mod int_encoding;
15mod klvm_decoder;
16mod klvm_encoder;
17mod macros;
18mod match_byte;
19mod to_klvm;
20mod wrappers;
21
22pub use error::*;
23pub use from_klvm::*;
24pub use int_encoding::*;
25pub use klvm_decoder::*;
26pub use klvm_encoder::*;
27pub use match_byte::*;
28pub use to_klvm::*;
29pub use wrappers::*;
30
31pub use klvmr::Atom;
32
33#[cfg(test)]
34#[cfg(feature = "derive")]
35mod derive_tests {
36 extern crate self as klvm_traits;
37
38 use super::*;
39
40 use std::fmt::Debug;
41
42 use klvmr::{serde::node_to_bytes, Allocator};
43
44 fn check<T>(value: &T, expected: &str)
45 where
46 T: Debug + PartialEq + ToKlvm<Allocator> + FromKlvm<Allocator>,
47 {
48 let a = &mut Allocator::new();
49
50 let ptr = value.to_klvm(a).unwrap();
51
52 let actual = node_to_bytes(a, ptr).unwrap();
53 assert_eq!(expected, hex::encode(actual));
54
55 let round_trip = T::from_klvm(a, ptr).unwrap();
56 assert_eq!(value, &round_trip);
57 }
58
59 fn coerce_into<A, B>(value: A) -> B
60 where
61 A: ToKlvm<Allocator>,
62 B: FromKlvm<Allocator>,
63 {
64 let a = &mut Allocator::new();
65 let ptr = value.to_klvm(a).unwrap();
66 B::from_klvm(a, ptr).unwrap()
67 }
68
69 #[test]
70 fn test_list_struct() {
71 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
72 #[klvm(list)]
73 struct Struct {
74 a: u64,
75 b: i32,
76 }
77
78 check(&Struct { a: 52, b: -32 }, "ff34ff81e080");
80 }
81
82 #[test]
83 fn test_list_struct_with_rest() {
84 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
85 #[klvm(list)]
86 struct Struct {
87 a: u64,
88 #[klvm(rest)]
89 b: i32,
90 }
91
92 check(&Struct { a: 52, b: -32 }, "ff3481e0");
94 }
95
96 #[test]
97 fn test_solution_struct() {
98 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
99 #[klvm(list)]
100 struct Struct {
101 a: u64,
102 b: i32,
103 }
104
105 check(&Struct { a: 52, b: -32 }, "ff34ff81e080");
107
108 let mut allocator = Allocator::new();
110 let ptr = klvm_list!(100, 200, 300, 400)
111 .to_klvm(&mut allocator)
112 .unwrap();
113 let value = Struct::from_klvm(&allocator, ptr).unwrap();
114 assert_eq!(value, Struct { a: 100, b: 200 });
115
116 let mut allocator = Allocator::new();
118 let ptr = klvm_list!([1, 2, 3], 200, 300)
119 .to_klvm(&mut allocator)
120 .unwrap();
121 Struct::from_klvm(&allocator, ptr).unwrap_err();
122 }
123
124 #[test]
125 fn test_solution_struct_with_rest() {
126 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
127 #[klvm(list)]
128 struct Struct {
129 a: u64,
130 #[klvm(rest)]
131 b: i32,
132 }
133
134 check(&Struct { a: 52, b: -32 }, "ff3481e0");
136
137 let mut allocator = Allocator::new();
139 let ptr = klvm_list!(100, 200, 300, 400)
140 .to_klvm(&mut allocator)
141 .unwrap();
142 Struct::from_klvm(&allocator, ptr).unwrap_err();
143 }
144
145 #[test]
146 fn test_curry_struct() {
147 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
148 #[klvm(curry)]
149 struct Struct {
150 a: u64,
151 b: i32,
152 }
153
154 check(
155 &Struct { a: 52, b: -32 },
156 "ff04ffff0134ffff04ffff0181e0ff018080",
157 );
158 }
159
160 #[test]
161 fn test_curry_struct_with_rest() {
162 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
163 #[klvm(curry)]
164 struct Struct {
165 a: u64,
166 #[klvm(rest)]
167 b: i32,
168 }
169
170 check(&Struct { a: 52, b: -32 }, "ff04ffff0134ff81e080");
171 }
172
173 #[test]
174 fn test_tuple_struct() {
175 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
176 #[klvm(list)]
177 struct Struct(String, String);
178
179 check(&Struct("A".to_string(), "B".to_string()), "ff41ff4280");
180 }
181
182 #[test]
183 fn test_newtype_struct() {
184 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
185 #[klvm(list)]
186 struct Struct(#[klvm(rest)] String);
187
188 check(&Struct("XYZ".to_string()), "8358595a");
189 }
190
191 #[test]
192 fn test_optional() {
193 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
194 #[klvm(list)]
195 struct Struct {
196 a: u64,
197 #[klvm(default)]
198 b: Option<i32>,
199 }
200
201 check(
202 &Struct {
203 a: 52,
204 b: Some(-32),
205 },
206 "ff34ff81e080",
207 );
208 check(&Struct { a: 52, b: None }, "ff3480");
209 }
210
211 #[test]
212 fn test_default() {
213 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
214 #[klvm(list)]
215 struct Struct {
216 a: u64,
217 #[klvm(default = 42)]
218 b: i32,
219 }
220
221 check(&Struct { a: 52, b: 32 }, "ff34ff2080");
222 check(&Struct { a: 52, b: 42 }, "ff3480");
223 }
224
225 #[test]
226 fn test_default_owned() {
227 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
228 #[klvm(list)]
229 struct Struct {
230 a: u64,
231 #[klvm(default = "Hello".to_string())]
232 b: String,
233 }
234
235 check(
236 &Struct {
237 a: 52,
238 b: "World".to_string(),
239 },
240 "ff34ff85576f726c6480",
241 );
242 check(
243 &Struct {
244 a: 52,
245 b: "Hello".to_string(),
246 },
247 "ff3480",
248 );
249 }
250
251 #[test]
252 fn test_constants() {
253 #[derive(ToKlvm, FromKlvm)]
254 #[apply_constants]
255 #[derive(Debug, PartialEq)]
256 #[klvm(list)]
257 struct RunTailCondition<P, S> {
258 #[klvm(constant = 51)]
259 opcode: u8,
260 #[klvm(constant = ())]
261 blank_puzzle_hash: (),
262 #[klvm(constant = -113)]
263 magic_amount: i8,
264 puzzle: P,
265 solution: S,
266 }
267
268 check(
269 &RunTailCondition {
270 puzzle: "puzzle".to_string(),
271 solution: "solution".to_string(),
272 },
273 "ff33ff80ff818fff8670757a7a6c65ff88736f6c7574696f6e80",
274 );
275 }
276
277 #[test]
278 fn test_enum() {
279 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
280 #[klvm(list)]
281 enum Enum {
282 A(i32),
283 B { x: i32 },
284 C,
285 }
286
287 check(&Enum::A(32), "ff80ff2080");
288 check(&Enum::B { x: -72 }, "ff01ff81b880");
289 check(&Enum::C, "ff0280");
290 }
291
292 #[test]
293 fn test_explicit_discriminant() {
294 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
295 #[klvm(list)]
296 #[repr(u8)]
297 enum Enum {
298 A(i32) = 42,
299 B { x: i32 } = 34,
300 C = 11,
301 }
302
303 check(&Enum::A(32), "ff2aff2080");
304 check(&Enum::B { x: -72 }, "ff22ff81b880");
305 check(&Enum::C, "ff0b80");
306 }
307
308 #[test]
309 fn test_untagged_enum() {
310 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
312 #[klvm(proper_list, untagged)]
313 enum Enum {
314 A(i32),
315 B {
316 x: i32,
317 y: i32,
318 },
319 #[klvm(curry)]
320 C {
321 curried_value: String,
322 },
323 }
324
325 check(&Enum::A(32), "ff2080");
326 check(&Enum::B { x: -72, y: 94 }, "ff81b8ff5e80");
327 check(
328 &Enum::C {
329 curried_value: "Hello".to_string(),
330 },
331 "ff04ffff018548656c6c6fff0180",
332 );
333 }
334
335 #[test]
336 fn test_untagged_enum_parsing_order() {
337 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
338 #[klvm(list, untagged)]
339 enum Enum {
340 A(i32),
342 B(i32),
344 C(String),
346 }
347
348 assert_eq!(coerce_into::<Enum, Enum>(Enum::A(32)), Enum::A(32));
350
351 assert_eq!(coerce_into::<Enum, Enum>(Enum::B(32)), Enum::A(32));
353
354 assert_eq!(
357 coerce_into::<Enum, Enum>(Enum::C("Hi".into())),
358 Enum::A(18537)
359 );
360
361 assert_eq!(
364 coerce_into::<Enum, Enum>(Enum::C("Hello, world!".into())),
365 Enum::C("Hello, world!".into())
366 );
367 }
368
369 #[test]
370 fn test_custom_crate_name() {
371 use klvm_traits as klvm_traits2;
372 #[derive(Debug, ToKlvm, FromKlvm, PartialEq)]
373 #[klvm(list, crate_name = klvm_traits2)]
374 struct Struct {
375 a: u64,
376 b: i32,
377 }
378
379 check(&Struct { a: 52, b: -32 }, "ff34ff81e080");
380 }
381}