cosmian_wit_bindgen_rust/
exports.rs

1use std::fmt;
2use std::marker;
3
4#[link(wasm_import_module = "wit_canonical_buffer_abi")]
5extern "C" {
6    fn in_len(handle: i32) -> usize;
7    fn in_read(handle: i32, amount: usize, dst: *mut u8);
8    fn out_len(handle: i32) -> usize;
9    fn out_write(handle: i32, amount: usize, dst: *const u8);
10}
11
12/// Implementation of `(in-buffer T)` for raw types `T` that can be directly
13/// copied into.
14pub struct InBufferRaw<'a, T> {
15    handle: i32,
16    _marker: marker::PhantomData<&'a T>,
17}
18
19impl<'a, T> InBufferRaw<'a, T> {
20    /// Only intended for adapter use.
21    ///
22    /// `unsafe` because this requires a valid `handle` and also requires `T` to
23    /// be valid to copy into. Additionally requires a valid `'a`
24    pub unsafe fn new(handle: i32) -> InBufferRaw<'a, T> {
25        InBufferRaw {
26            handle,
27            _marker: marker::PhantomData,
28        }
29    }
30
31    /// Returns the length of the buffer provided by the caller.
32    ///
33    /// Returns the number of items, in units of `T`, that are available to
34    /// `copy` to receive.
35    pub fn len(&self) -> usize {
36        unsafe { in_len(self.handle) }
37    }
38
39    /// Copies elements from the caller into `space`.
40    ///
41    /// This will abort the program if `space` is larger than `self.len()`.
42    /// Otherwise the `space` array will be entirely filled upon returning.
43    pub fn copy(&self, space: &mut [T]) {
44        unsafe {
45            in_read(self.handle, space.len(), space.as_mut_ptr() as *mut u8);
46        }
47    }
48}
49
50impl<T> fmt::Debug for InBufferRaw<'_, T> {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        f.debug_struct("InBufferRaw")
53            .field("handle", &self.handle)
54            .field("len", &self.len())
55            .finish()
56    }
57}
58
59/// Implementation of `(in-buffer T)`
60pub struct InBuffer<'a, T> {
61    handle: i32,
62    deserialize: fn(i32) -> T,
63    element_size: usize,
64    _marker: marker::PhantomData<&'a T>,
65}
66
67impl<'a, T> InBuffer<'a, T> {
68    /// Only intended for adapter use.
69    pub unsafe fn new(
70        handle: i32,
71        element_size: i32,
72        deserialize: fn(i32) -> T,
73    ) -> InBuffer<'a, T> {
74        InBuffer {
75            handle,
76            element_size: element_size as u32 as usize,
77            deserialize,
78            _marker: marker::PhantomData,
79        }
80    }
81
82    /// Returns the length of the buffer provided by the caller.
83    ///
84    /// Returns the number of items, in units of `T`, that are available to
85    /// `iter` to copy in.
86    pub fn len(&self) -> usize {
87        unsafe { in_len(self.handle) }
88    }
89
90    /// Returns the size of a `T` to gauge how much scratch space to pass to
91    /// [`InBuffer::iter`].
92    pub fn element_size(&self) -> usize {
93        self.element_size
94    }
95
96    /// Copies items from the caller into `scratch` and then returns an
97    /// iterator over the deserialized versions.
98    ///
99    /// The `scratch` buffer should be appropriately sized for the number of
100    /// items you wish to iterate over.
101    pub fn iter<'b>(&self, scratch: &'b mut [u8]) -> impl ExactSizeIterator<Item = T> + 'b
102    where
103        'a: 'b,
104    {
105        // TODO: need to deserialize/drop remaining items if the iterator
106        // doesn't finish
107        unsafe {
108            let element_size = self.element_size;
109            let len = scratch.len() / element_size;
110            in_read(self.handle, len, scratch.as_mut_ptr());
111            let deserialize = self.deserialize;
112            (0..len).map(move |i| {
113                deserialize(scratch[i * element_size..][..element_size].as_ptr() as i32)
114            })
115        }
116    }
117}
118
119impl<T> fmt::Debug for InBuffer<'_, T> {
120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121        f.debug_struct("InBuffer")
122            .field("handle", &self.handle)
123            .field("len", &self.len())
124            .finish()
125    }
126}
127
128/// Implementation of `(out-buffer T)` for raw types `T` that can be directly
129/// copied to the caller.
130pub struct OutBufferRaw<'a, T> {
131    handle: i32,
132    _marker: marker::PhantomData<&'a mut T>,
133}
134
135impl<'a, T> OutBufferRaw<'a, T> {
136    /// Only intended for adapter use.
137    ///
138    /// `unsafe` because this requires a valid `handle`, requires `T` to
139    /// be valid to copy into, and requires a valid `'a`.
140    pub unsafe fn new(handle: i32) -> OutBufferRaw<'a, T> {
141        OutBufferRaw {
142            handle,
143            _marker: marker::PhantomData,
144        }
145    }
146
147    /// Returns the capacity of the buffer provided by the caller.
148    ///
149    /// Returns the number of items, in units of `T`, that are available to
150    /// `write` to receive.
151    pub fn capacity(&self) -> usize {
152        unsafe { out_len(self.handle) }
153    }
154
155    /// Copies elements to the caller from `items`.
156    ///
157    /// This will abort the program if `items` is larger than `self.capacity()`.
158    pub fn write(&self, items: &[T]) {
159        unsafe {
160            out_write(self.handle, items.len(), items.as_ptr() as *const u8);
161        }
162    }
163}
164
165impl<T> fmt::Debug for OutBufferRaw<'_, T> {
166    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167        f.debug_struct("OutBufferRaw")
168            .field("handle", &self.handle)
169            .field("capacity", &self.capacity())
170            .finish()
171    }
172}
173
174/// Implementation of `(in-buffer T)`
175pub struct OutBuffer<'a, T> {
176    handle: i32,
177    serialize: fn(i32, T),
178    element_size: usize,
179    _marker: marker::PhantomData<&'a mut T>,
180}
181
182impl<'a, T> OutBuffer<'a, T> {
183    /// Only intended for adapter use.
184    pub unsafe fn new(handle: i32, element_size: i32, serialize: fn(i32, T)) -> OutBuffer<'a, T> {
185        OutBuffer {
186            handle,
187            element_size: element_size as u32 as usize,
188            serialize,
189            _marker: marker::PhantomData,
190        }
191    }
192
193    /// Returns the capacity of the buffer provided by the caller.
194    ///
195    /// Returns the number of items, in units of `T`, that are available to
196    /// `iter` to copy in.
197    pub fn capacity(&self) -> usize {
198        unsafe { out_len(self.handle) }
199    }
200
201    /// Returns the size of a `T` to gauge how much scratch space to pass to
202    /// [`OutBuffer::write`].
203    pub fn element_size(&self) -> usize {
204        self.element_size
205    }
206
207    /// Writes items into this buffer.
208    ///
209    /// This method will write the `items` provided into this buffer to get
210    /// passed to the caller. The `scratch` space provided must be large enough
211    /// to contain the encoded size of all of `items`, and the amount of
212    /// `scratch` needed can be gauged with the [`OutBuffer::element_size`]
213    /// method.
214    pub fn write(&self, scratch: &mut [u8], items: impl ExactSizeIterator<Item = T>) {
215        assert!(items.len().checked_mul(self.element_size).unwrap() <= scratch.len());
216        let mut len = 0;
217        // TODO: if `items` ends up being longer than expected then we leak all
218        // items previously serialized.
219        for (i, item) in items.enumerate() {
220            len += 1;
221            (self.serialize)(
222                scratch[i * self.element_size..][..self.element_size].as_mut_ptr() as i32,
223                item,
224            );
225        }
226        unsafe {
227            out_write(self.handle, len, scratch.as_ptr());
228        }
229    }
230}
231
232impl<T> fmt::Debug for OutBuffer<'_, T> {
233    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234        f.debug_struct("OutBuffer")
235            .field("handle", &self.handle)
236            .field("capacity", &self.capacity())
237            .finish()
238    }
239}