mod error;
mod field;
mod hash;
mod schema;
use std::num::NonZeroU16;
#[cfg(feature = "serde")]
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
pub use error::{SchemaError, SchemaResult};
pub use field::{ChangePolicy, FieldCodec, FieldDef, FixedPoint};
pub use hash::schema_hash;
pub use schema::{ComponentDef, Schema, SchemaBuilder};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ComponentId(NonZeroU16);
impl ComponentId {
#[must_use]
pub const fn new(value: u16) -> Option<Self> {
match NonZeroU16::new(value) {
Some(value) => Some(Self(value)),
None => None,
}
}
#[must_use]
pub const fn get(self) -> u16 {
self.0.get()
}
}
#[cfg(feature = "serde")]
impl Serialize for ComponentId {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_u16(self.get())
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for ComponentId {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let value = u16::deserialize(deserializer)?;
ComponentId::new(value).ok_or_else(|| D::Error::custom("component id must be non-zero"))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct FieldId(NonZeroU16);
impl FieldId {
#[must_use]
pub const fn new(value: u16) -> Option<Self> {
match NonZeroU16::new(value) {
Some(value) => Some(Self(value)),
None => None,
}
}
#[must_use]
pub const fn get(self) -> u16 {
self.0.get()
}
}
#[cfg(feature = "serde")]
impl Serialize for FieldId {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_u16(self.get())
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for FieldId {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let value = u16::deserialize(deserializer)?;
FieldId::new(value).ok_or_else(|| D::Error::custom("field id must be non-zero"))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem::size_of;
#[test]
fn public_api_exports() {
let _ = FieldCodec::bool();
let _ = ChangePolicy::Always;
let _ = FieldDef::new(FieldId::new(1).unwrap(), FieldCodec::bool());
let _ = Schema::builder();
let _ = schema_hash(&Schema::new(Vec::new()).unwrap());
let _: ComponentId = ComponentId::new(1).unwrap();
let _: FieldId = FieldId::new(1).unwrap();
}
#[test]
fn field_codec_basic_usage() {
let codec = FieldCodec::bool();
assert!(matches!(codec, FieldCodec::Bool));
}
#[test]
fn schema_hash_basic() {
let schema = Schema::new(Vec::new()).unwrap();
assert_ne!(schema_hash(&schema), 0);
}
#[test]
fn component_id_and_field_id_sizes() {
assert_eq!(size_of::<ComponentId>(), 2);
assert_eq!(size_of::<FieldId>(), 2);
}
#[test]
fn component_id_zero_is_invalid() {
assert!(ComponentId::new(0).is_none());
}
#[test]
fn field_id_zero_is_invalid() {
assert!(FieldId::new(0).is_none());
}
}