Skip to content

Instantly share code, notes, and snippets.

@sqrtM
Last active October 13, 2023 17:16
Show Gist options
  • Save sqrtM/9a3a1522e2b5728989644ae35e879d6a to your computer and use it in GitHub Desktop.
Save sqrtM/9a3a1522e2b5728989644ae35e879d6a to your computer and use it in GitHub Desktop.
serde arrays of arbitrary size
/// works for any T where T implements copy and default.
mod array_serde {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S, T: Serialize>(array: &[T], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
array.serialize(serializer)
}
pub fn deserialize<'de, D, const N: usize, T>(deserializer: D) -> Result<[T; N], D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Default + Copy,
{
let vec: Vec<T> = Vec::deserialize(deserializer)?;
if vec.len() == N {
let mut array = [T::default(); N];
array.copy_from_slice(&vec);
Ok(array)
} else {
Err(serde::de::Error::custom(format!(
"Expected array of length {}, found {}",
N,
vec.len()
)))
}
}
}
/// it's definitely possible to get away with using this
/// for non-copy types, but it would (probably?) require
/// some unsafety, like:
///
/// let vec: Vec<T> = Vec::deserialize(deserializer)?;
/// if vec.len() == N {
/// let mut array: [T; N] = std::array::from_fn(|_| T::default());
/// for (i, v) in vec.into_iter().enumerate() {
/// // Use MaybeUninit and transmute to safely handle non-cloneable types.
/// let mut uninitialized = std::mem::MaybeUninit::uninit();
/// std::ptr::copy_nonoverlapping(&v as *const T, uninitialized.as_mut_ptr(), 1);
/// array[i] = unsafe { uninitialized.assume_init() };
/// }
/// Ok(array)
///
/// ... or something.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment