Last active
October 13, 2023 17:16
-
-
Save sqrtM/9a3a1522e2b5728989644ae35e879d6a to your computer and use it in GitHub Desktop.
serde arrays of arbitrary size
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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