nibblecode 0.1.0

A serialization format based on rkyv
Documentation
use std::any::type_name;
use std::mem::{MaybeUninit, offset_of};
use std::ptr::Alignment;

use crate::option::ArchivedOption;
use crate::{Serialize, SerializeError, VerifyError};

impl<T: Serialize> Serialize for Option<T> {
	type Archived = ArchivedOption<T::Archived>;
	const ALIGN: Alignment = T::ALIGN;
	const COPY_OPTIMIZATION: bool = T::COPY_OPTIMIZATION
		&& offset_of!(Option<T>, Some.0) == offset_of!(ArchivedOption<T::Archived>, Some.0);

	unsafe fn serialize(
		&self,
		out: *mut MaybeUninit<ArchivedOption<T::Archived>>,
		heap: *mut MaybeUninit<u8>,
	) -> usize {
		unsafe {
			if let Some(val) = self {
				*out.cast::<u8>() = 1;
				val.serialize(
					out.cast::<u8>()
						.add(offset_of!(ArchivedOption<T::Archived>, Some.0))
						.cast(),
					heap,
				)
			} else {
				*out = MaybeUninit::new(ArchivedOption::None);
				0
			}
		}
	}

	fn serialized_size(&self, offset: usize) -> Result<usize, SerializeError> {
		if let Some(val) = self {
			val.serialized_size(offset)
		} else {
			Ok(0)
		}
	}

	#[inline]
	unsafe fn verify(
		this: *const ArchivedOption<T::Archived>,
		buffer_end: *const u8,
	) -> Result<(), VerifyError> {
		unsafe {
			let tag = *this.cast::<u8>();
			match tag {
				0 => Ok(()),
				1 => T::verify(
					this.cast::<u8>()
						.add(offset_of!(ArchivedOption<T::Archived>, Some.0))
						.cast(),
					buffer_end,
				),
				_ => Err(VerifyError::InvalidEnumDiscriminantError {
					enum_name: type_name::<Option<T>>(),
					invalid_discriminant: tag,
				}),
			}
		}
	}
}

#[cfg(test)]
mod tests {
	use crate::test::roundtrip;

	#[test]
	fn roundtrip_option() {
		roundtrip(&Option::<()>::None);
		roundtrip(&Some(42));
	}
}