Skip to main content

specta_util/
array.rs

1use std::marker::PhantomData;
2
3use specta::{
4    Type, Types,
5    datatype::{DataType, List},
6};
7
8/// Declares a fixed-length array type for Specta exporters.
9///
10/// This is primarily useful with `#[specta(type = ...)]` when you want an array
11/// field to keep its length information in exported schemas.
12///
13/// A plain Rust array like `[u8; 2]` may be exported as `number[]` if Specta
14/// deems it's unable to safely export it as `[number, number]`. This limitation
15/// is due to the fact that Specta can't track the inference of const generics and
16/// hence can't fully support them. Using `FixedArray<N, T>` will always encode the
17/// length so it can be used to force override Specta's conservative behaviour when you know what your doing.
18///
19/// ```ignore
20/// use specta::Type;
21///
22/// /// #[derive(Type)]
23/// struct DemoA {
24///     a: [u8; 2],     // becomes `[number, number]`
25///
26///     #[specta(type = specta_util::FixedArray<2, u8>)]
27///     d: [u8; 2],     // becomes `[number, number]`
28/// }
29///
30/// #[derive(Type)]
31/// struct DemoB<const N: usize = 1> {
32///     // These are generalised by Specta as we can't know if a specific type is using `N` or a constant, and we don't know what `N` is.
33///     // If you `#[specta(inline)]` or `#[serde(flatten)]` the `[number, number]` will be restored as we are able to track it properly.
34///     data: [u32; N], // becomes `number[]`
35///     a: [u8; 2],     // becomes `number[]`
36///
37///     #[specta(type = specta_util::FixedArray<2, u8>)]
38///     d: [u8; 2],     // becomes `[number, number]`
39/// }
40/// ```
41pub struct FixedArray<const N: usize, T: Type>(PhantomData<[T; N]>);
42
43impl<const N: usize, T: Type> Type for FixedArray<N, T> {
44    fn definition(types: &mut Types) -> DataType {
45        let mut l = List::new(T::definition(types));
46        // Refer to the type documentation for the safety around this.
47        l.length = Some(N);
48        DataType::List(l)
49    }
50}