linera_witty/type_traits/implementations/
frunk.rs1use std::{borrow::Cow, ops::Add};
7
8use frunk::{HCons, HList, HNil};
9
10use crate::{
11 GuestPointer, InstanceWithMemory, Layout, Memory, Runtime, RuntimeError, RuntimeMemory, Split,
12 WitLoad, WitStore, WitType,
13};
14
15impl WitType for HNil {
16 const SIZE: u32 = 0;
17
18 type Layout = HNil;
19 type Dependencies = HNil;
20
21 fn wit_type_name() -> Cow<'static, str> {
22 "hnil".into()
23 }
24
25 fn wit_type_declaration() -> Cow<'static, str> {
26 "type hnil = unit".into()
27 }
28}
29
30impl WitLoad for HNil {
31 fn load<Instance>(
32 _memory: &Memory<'_, Instance>,
33 _location: GuestPointer,
34 ) -> Result<Self, RuntimeError>
35 where
36 Instance: InstanceWithMemory,
37 {
38 Ok(HNil)
39 }
40
41 fn lift_from<Instance>(
42 HNil: <Self::Layout as Layout>::Flat,
43 _memory: &Memory<'_, Instance>,
44 ) -> Result<Self, RuntimeError>
45 where
46 Instance: InstanceWithMemory,
47 {
48 Ok(HNil)
49 }
50}
51
52impl WitStore for HNil {
53 fn store<Instance>(
54 &self,
55 _memory: &mut Memory<'_, Instance>,
56 _location: GuestPointer,
57 ) -> Result<(), RuntimeError>
58 where
59 Instance: InstanceWithMemory,
60 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
61 {
62 Ok(())
63 }
64
65 fn lower<Instance>(
66 &self,
67 _memory: &mut Memory<'_, Instance>,
68 ) -> Result<<Self::Layout as Layout>::Flat, RuntimeError>
69 where
70 Instance: InstanceWithMemory,
71 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
72 {
73 Ok(HNil)
74 }
75}
76
77impl<Head, Tail> WitType for HCons<Head, Tail>
78where
79 Head: WitType,
80 Tail: WitType + SizeCalculation,
81 Head::Layout: Add<Tail::Layout>,
82 <Head::Layout as Add<Tail::Layout>>::Output: Layout,
83{
84 const SIZE: u32 = {
85 let packed_size = Self::SIZE_STARTING_AT_BYTE_BOUNDARIES[0];
86 let aligned_size = GuestPointer(packed_size).after_padding_for::<Self>();
87
88 aligned_size.0
89 };
90
91 type Layout = <Head::Layout as Add<Tail::Layout>>::Output;
92 type Dependencies = HList![Head, Tail];
93
94 fn wit_type_name() -> Cow<'static, str> {
95 format!("hcons-{}-{}", Head::wit_type_name(), Tail::wit_type_name()).into()
96 }
97
98 fn wit_type_declaration() -> Cow<'static, str> {
99 let head = Head::wit_type_name();
100 let tail = Tail::wit_type_name();
101
102 format!("type hcons-{head}-{tail} = tuple<{head}, {tail}>").into()
103 }
104}
105
106impl<Head, Tail> WitLoad for HCons<Head, Tail>
107where
108 Head: WitLoad,
109 Tail: WitLoad + SizeCalculation,
110 Head::Layout: Add<Tail::Layout>,
111 <Head::Layout as Add<Tail::Layout>>::Output: Layout,
112 <Self::Layout as Layout>::Flat:
113 Split<<Head::Layout as Layout>::Flat, Remainder = <Tail::Layout as Layout>::Flat>,
114{
115 fn load<Instance>(
116 memory: &Memory<'_, Instance>,
117 location: GuestPointer,
118 ) -> Result<Self, RuntimeError>
119 where
120 Instance: InstanceWithMemory,
121 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
122 {
123 Ok(HCons {
124 head: Head::load(memory, location)?,
125 tail: Tail::load(
126 memory,
127 location
128 .after::<Head>()
129 .after_padding_for::<Tail::FirstElement>(),
130 )?,
131 })
132 }
133
134 fn lift_from<Instance>(
135 layout: <Self::Layout as Layout>::Flat,
136 memory: &Memory<'_, Instance>,
137 ) -> Result<Self, RuntimeError>
138 where
139 Instance: InstanceWithMemory,
140 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
141 {
142 let (head_layout, tail_layout) = layout.split();
143
144 Ok(HCons {
145 head: Head::lift_from(head_layout, memory)?,
146 tail: Tail::lift_from(tail_layout, memory)?,
147 })
148 }
149}
150
151impl<Head, Tail> WitStore for HCons<Head, Tail>
152where
153 Head: WitStore,
154 Tail: WitStore + SizeCalculation,
155 Head::Layout: Add<Tail::Layout>,
156 <Head::Layout as Add<Tail::Layout>>::Output: Layout,
157 <Head::Layout as Layout>::Flat: Add<<Tail::Layout as Layout>::Flat>,
158 Self::Layout: Layout<
159 Flat = <<Head::Layout as Layout>::Flat as Add<<Tail::Layout as Layout>::Flat>>::Output,
160 >,
161{
162 fn store<Instance>(
163 &self,
164 memory: &mut Memory<'_, Instance>,
165 location: GuestPointer,
166 ) -> Result<(), RuntimeError>
167 where
168 Instance: InstanceWithMemory,
169 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
170 {
171 self.head.store(memory, location)?;
172 self.tail.store(
173 memory,
174 location
175 .after::<Head>()
176 .after_padding_for::<Tail::FirstElement>(),
177 )?;
178
179 Ok(())
180 }
181
182 fn lower<Instance>(
183 &self,
184 memory: &mut Memory<'_, Instance>,
185 ) -> Result<<Self::Layout as Layout>::Flat, RuntimeError>
186 where
187 Instance: InstanceWithMemory,
188 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
189 {
190 let head_layout = self.head.lower(memory)?;
191 let tail_layout = self.tail.lower(memory)?;
192
193 Ok(head_layout + tail_layout)
194 }
195}
196
197trait SizeCalculation {
202 const SIZE_STARTING_AT_BYTE_BOUNDARIES: [u32; 8];
205
206 type FirstElement: WitType;
209}
210
211impl SizeCalculation for HNil {
212 const SIZE_STARTING_AT_BYTE_BOUNDARIES: [u32; 8] = [0; 8];
213
214 type FirstElement = ();
215}
216
217macro_rules! unroll_for {
219 ($binding:ident in [ $($elements:expr),* $(,)? ] $body:tt) => {
220 $(
221 let $binding = $elements;
222 $body
223 )*
224 };
225}
226
227impl<Head, Tail> SizeCalculation for HCons<Head, Tail>
228where
229 Head: WitType,
230 Tail: SizeCalculation,
231{
232 const SIZE_STARTING_AT_BYTE_BOUNDARIES: [u32; 8] = {
233 let mut size_at_boundaries = [0; 8];
234
235 unroll_for!(boundary_offset in [0, 1, 2, 3, 4, 5, 6, 7] {
236 let memory_location = GuestPointer(boundary_offset)
237 .after_padding_for::<Head>()
238 .after::<Head>();
239
240 let tail_size = Tail::SIZE_STARTING_AT_BYTE_BOUNDARIES[memory_location.0 as usize % 8];
241
242 size_at_boundaries[boundary_offset as usize] =
243 memory_location.0 - boundary_offset + tail_size;
244 });
245
246 size_at_boundaries
247 };
248
249 type FirstElement = Head;
250}