use alux_ext::ext;
use alux_ext::macros::shape;
use alux_shape::{FieldAlg, ShapeAlg, ShapeDeclareExt, ShapeExt, ShapeProgramExt, Sorts, Spelling};
use alux_shape_rust::RustShape;
use alux_shape_text::TextShape;
#[ext(name = LeafExt, supertraits = Sorts + Sized)]
pub impl<This> This
where
This: ShapeAlg,
{
fn checksum(&self) -> Self::Ty {
self.bytes_hex(Some(32))
}
fn amount(&self) -> Self::Ty {
self.int_decimal(false, 128)
}
}
#[ext(name = AccountShapeExt, defunc(via = shape))]
pub impl<This> This
where
This: ShapeAlg + FieldAlg,
{
fn timestamps_shape(&self) {
self.record().field(created_at, self.int(false, 64))
}
fn account_shape(&self) {
self.record()
.field(display_name, self.text())
.field(balance, self.amount())
.field(checksum, self.checksum())
.merge(self.timestamps_shape())
}
}
fn rust() -> RustShape {
RustShape::new(Spelling::LowerCamel)
}
#[test]
fn a_declaration_states_a_layout_no_one_wrote() {
let layout = rust().compile_shape(rust().account_shape());
assert_eq!(layout.ty(), "Account");
assert_eq!(
layout.module(),
[
"#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]",
"#[serde(rename_all = \"camelCase\")]",
"pub struct Account {",
" pub display_name: String,",
" pub balance: Decimal<u128>,",
" pub checksum: Hex<[u8; 32]>,",
" #[serde(flatten)]",
" pub timestamps: Timestamps,",
"}",
"",
"#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]",
"#[serde(rename_all = \"camelCase\")]",
"pub struct Timestamps {",
" pub created_at: u64,",
"}",
]
.join("\n"),
);
}
#[test]
fn one_declaration_answers_to_whichever_interpretation_folds_it() {
assert_eq!(rust().compile_shape(rust().account_shape()).ty(), "Account");
assert_eq!(
TextShape.compile_shape(TextShape.account_shape()),
"account { display_name: text, balance: decimal u128, checksum: hex bytes<32>, \
..timestamps { created_at: u64 } }",
);
}