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
//! HList-based static ciphertext shape (opt-in via the `hlist` feature).
//!
//! # Why a second design?
//!
//! The default [`Cipher`](crate::Cipher) / `AesCipherText` path uses a
//! recursive enum, with a `Vec` per nested container and a
//! `Box<dyn Any + Send>` for passthrough values. This is the right trade-off
//! for wasm32 / JS bindings (dynamic shapes, smaller monomorphisation
//! footprint) and for code paths whose structure is only known at runtime.
//!
//! This module provides a parallel, **statically-shaped** encoding for
//! performance-sensitive native Rust code where:
//!
//! - the ciphertext schema is known at compile time (typically derive-macro
//! generated `Encrypt` / `Decrypt` impls for fixed structs),
//! - the cost of `Box<dyn Any>` allocation + downcast on every passthrough is
//! undesirable, or
//! - passthrough must remain typed end-to-end with no runtime fallibility.
//!
//! # Shape
//!
//! Each cipher operation produces a *different* output type. The builder
//! threads them into an [`HList`] so the final container type literally
//! describes the encrypted structure:
//!
//! ```text
//! Map<HCons<Entry<Passthrough<u8>>, HCons<Entry<Encrypted>, HNil>>>
//! // └── passthrough u8 field └── encrypted bytes field
//! ```
//!
//! Decryption is destructuring — no shape check, no downcast, no allocation
//! for the structural nodes. The leaf ciphertexts (`Encrypted`, `Absent`)
//! still carry their `LocalCipherText` payload.
//!
//! # Trade-offs
//!
//! - **Single `Cipher::Ok` is impossible**: a separate trait,
//! [`StaticCipher`], replaces [`Cipher`](crate::Cipher) here. The two trait
//! hierarchies coexist behind the feature flag.
//! - **Homogeneous `Vec<_>` of varying length is not expressible** in HList
//! form — `Vec<Encrypted>` of uniform primitives still works, but the
//! dynamic path's `Vec<AesCipherText>` does not have a direct equivalent.
//! - **Type spellings are large**. A derive macro should generate the
//! `type FooCiphertext = Map<HCons<...>>` aliases; humans should rarely
//! write them by hand.
pub use ;
pub use ;
/// The empty HList — terminates an [`HCons`] chain.
;
/// One cell of an HList: head element `H` plus tail HList `T`.
;
/// Marker for types that form a well-formed (terminated) HList.
/// Construct an HList literal: `hlist![1, "two", 3.0]`.
/// Destructure an HList: `let hlist_pat![a, b, c] = list;`.