use super::FixedVector;
use super::FixedMatrix;
use super::tensor::Tensor;
use crate::fixed_point::core_types::errors::OverflowDetected;
use crate::fixed_point::fixed_num::FixedNum;
use crate::fixed_point::width::Storage;
use crate::fixed_point::Fixed;
const FORMAT_TAG: u8 = 0x20;
impl<S: Storage, const F: u32> Fixed<S, F>
where
Self: FixedNum<Storage = S>,
{
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::with_capacity(3 + S::BYTES);
bytes.extend_from_slice(&Self::format_tag());
bytes.extend_from_slice(&self.raw().to_be_vec());
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, OverflowDetected> {
if bytes.len() < 3 + S::BYTES || bytes[..3] != Self::format_tag() {
return Err(OverflowDetected::InvalidInput);
}
Ok(Self::from_raw(S::from_be_slice(&bytes[3..3 + S::BYTES])))
}
pub fn from_bytes_legacy(bytes: &[u8]) -> Result<Self, OverflowDetected> {
if bytes.len() < 1 + S::BYTES {
return Err(OverflowDetected::InvalidInput);
}
let accepted = match (S::CODE, bytes[0]) {
(1, 0x05) => true,
(1, t) => t & 0x80 != 0 && (t & 0x7F) as u32 == F,
(2, 0x04) | (3, 0x01) | (4, 0x02) | (5, 0x03) => true,
_ => false,
};
if !accepted {
return Err(OverflowDetected::InvalidInput);
}
Ok(Self::from_raw(S::from_be_slice(&bytes[1..1 + S::BYTES])))
}
pub fn to_raw_bytes(&self) -> Vec<u8> {
self.raw().to_be_vec()
}
pub fn from_raw_bytes(bytes: &[u8]) -> Result<Self, OverflowDetected> {
if bytes.len() < S::BYTES {
return Err(OverflowDetected::InvalidInput);
}
Ok(Self::from_raw(S::from_be_slice(&bytes[..S::BYTES])))
}
pub fn format_tag() -> [u8; 3] {
let f = (F as u16).to_be_bytes();
[FORMAT_TAG | S::CODE, f[0], f[1]]
}
pub fn legacy_tag() -> u8 {
match S::CODE {
1 => if F == 16 { 0x05 } else { 0x80 | F as u8 },
2 => 0x04,
3 => 0x01,
4 => 0x02,
_ => 0x03,
}
}
pub fn raw_byte_len() -> usize {
S::BYTES
}
}
impl<S: Storage, const F: u32> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
pub fn to_bytes(&self) -> Vec<u8> {
let n = self.len();
let mut bytes = Vec::with_capacity(4 + n * S::BYTES);
bytes.extend_from_slice(&(n as u32).to_be_bytes());
for i in 0..n {
bytes.extend_from_slice(&self[i].raw().to_be_vec());
}
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, OverflowDetected> {
if bytes.len() < 4 {
return Err(OverflowDetected::InvalidInput);
}
let n = u32::from_be_bytes(bytes[0..4].try_into().unwrap()) as usize;
let expected = 4 + n * S::BYTES;
if bytes.len() < expected {
return Err(OverflowDetected::InvalidInput);
}
let mut data = Vec::with_capacity(n);
for i in 0..n {
let start = 4 + i * S::BYTES;
data.push(Fixed::from_raw(S::from_be_slice(&bytes[start..start + S::BYTES])));
}
Ok(FixedVector::from_slice(&data))
}
}
impl<S: Storage, const F: u32> FixedMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
pub fn to_bytes(&self) -> Vec<u8> {
let n = self.rows() * self.cols();
let mut bytes = Vec::with_capacity(8 + n * S::BYTES);
bytes.extend_from_slice(&(self.rows() as u32).to_be_bytes());
bytes.extend_from_slice(&(self.cols() as u32).to_be_bytes());
for r in 0..self.rows() {
for c in 0..self.cols() {
bytes.extend_from_slice(&self.get(r, c).raw().to_be_vec());
}
}
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, OverflowDetected> {
if bytes.len() < 8 {
return Err(OverflowDetected::InvalidInput);
}
let rows = u32::from_be_bytes(bytes[0..4].try_into().unwrap()) as usize;
let cols = u32::from_be_bytes(bytes[4..8].try_into().unwrap()) as usize;
let n = rows * cols;
let expected = 8 + n * S::BYTES;
if bytes.len() < expected {
return Err(OverflowDetected::InvalidInput);
}
let mut m = FixedMatrix::new(rows, cols);
for i in 0..n {
let start = 8 + i * S::BYTES;
m.set(i / cols, i % cols, Fixed::from_raw(S::from_be_slice(&bytes[start..start + S::BYTES])));
}
Ok(m)
}
}
impl<S: Storage, const F: u32> Tensor<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
pub fn to_bytes(&self) -> Vec<u8> {
let rank = self.rank();
let total = self.len();
let mut bytes = Vec::with_capacity(1 + rank * 4 + total * S::BYTES);
bytes.push(rank as u8);
for &dim in self.shape() {
bytes.extend_from_slice(&(dim as u32).to_be_bytes());
}
for val in self.data() {
bytes.extend_from_slice(&val.raw().to_be_vec());
}
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, OverflowDetected> {
if bytes.is_empty() {
return Err(OverflowDetected::InvalidInput);
}
let rank = bytes[0] as usize;
let header_len = 1 + rank * 4;
if bytes.len() < header_len {
return Err(OverflowDetected::InvalidInput);
}
let mut shape = Vec::with_capacity(rank);
for i in 0..rank {
let offset = 1 + i * 4;
shape.push(u32::from_be_bytes(bytes[offset..offset + 4].try_into().unwrap()) as usize);
}
let total: usize = shape.iter().product::<usize>().max(1);
let expected = header_len + total * S::BYTES;
if bytes.len() < expected {
return Err(OverflowDetected::InvalidInput);
}
let mut data = Vec::with_capacity(total);
for i in 0..total {
let start = header_len + i * S::BYTES;
data.push(Fixed::from_raw(S::from_be_slice(&bytes[start..start + S::BYTES])));
}
Ok(Tensor::from_data(&shape, &data))
}
}
pub const MANIFOLD_TAG_EUCLIDEAN: u8 = 0x01;
pub const MANIFOLD_TAG_SPHERE: u8 = 0x02;
pub const MANIFOLD_TAG_HYPERBOLIC: u8 = 0x03;
pub const MANIFOLD_TAG_SPD: u8 = 0x04;
pub const MANIFOLD_TAG_GRASSMANNIAN: u8 = 0x05;
#[derive(Clone, Debug)]
pub struct ManifoldPoint<T> {
pub manifold_tag: u8,
pub params: Vec<u32>,
pub coordinates: FixedVector<T>,
}
impl<T> ManifoldPoint<T> {
pub fn euclidean(dim: usize, coords: FixedVector<T>) -> Self {
Self { manifold_tag: MANIFOLD_TAG_EUCLIDEAN, params: vec![dim as u32], coordinates: coords }
}
pub fn sphere(dim: usize, coords: FixedVector<T>) -> Self {
Self { manifold_tag: MANIFOLD_TAG_SPHERE, params: vec![dim as u32], coordinates: coords }
}
pub fn hyperbolic(dim: usize, coords: FixedVector<T>) -> Self {
Self { manifold_tag: MANIFOLD_TAG_HYPERBOLIC, params: vec![dim as u32], coordinates: coords }
}
pub fn spd(n: usize, coords: FixedVector<T>) -> Self {
Self { manifold_tag: MANIFOLD_TAG_SPD, params: vec![n as u32], coordinates: coords }
}
pub fn grassmannian(k: usize, n: usize, coords: FixedVector<T>) -> Self {
Self { manifold_tag: MANIFOLD_TAG_GRASSMANNIAN, params: vec![k as u32, n as u32], coordinates: coords }
}
}
impl<S: Storage, const F: u32> ManifoldPoint<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
pub fn to_bytes(&self) -> Vec<u8> {
let vec_bytes = self.coordinates.to_bytes();
let mut bytes = Vec::with_capacity(2 + self.params.len() * 4 + vec_bytes.len());
bytes.push(self.manifold_tag);
bytes.push(self.params.len() as u8);
for &p in &self.params {
bytes.extend_from_slice(&p.to_be_bytes());
}
bytes.extend_from_slice(&vec_bytes);
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, OverflowDetected> {
if bytes.len() < 2 {
return Err(OverflowDetected::InvalidInput);
}
let tag = bytes[0];
let num_params = bytes[1] as usize;
let params_end = 2 + num_params * 4;
if bytes.len() < params_end {
return Err(OverflowDetected::InvalidInput);
}
let mut params = Vec::with_capacity(num_params);
for i in 0..num_params {
let offset = 2 + i * 4;
params.push(u32::from_be_bytes(bytes[offset..offset + 4].try_into().unwrap()));
}
let coordinates = FixedVector::from_bytes(&bytes[params_end..])?;
Ok(Self { manifold_tag: tag, params, coordinates })
}
}
const COMPACT_ZERO: u8 = 0b000;
const COMPACT_SMALL: u8 = 0b010;
const COMPACT_MEDIUM: u8 = 0b100;
const COMPACT_FULL: u8 = 0b110;
const COMPACT_SIGN_BIT: u8 = 0b001;
impl<S: Storage, const F: u32> Fixed<S, F>
where
Self: FixedNum<Storage = S>,
{
pub fn to_compact_bytes(&self) -> Vec<u8> {
if self.is_zero() {
return vec![COMPACT_ZERO];
}
let is_neg = self.is_negative();
let Some(magnitude) = self.raw().checked_neg_wide().map(|neg| if is_neg { neg } else { self.raw() }) else {
let mut bytes = Vec::with_capacity(1 + S::BYTES);
bytes.push(COMPACT_FULL);
bytes.extend_from_slice(&self.raw().to_be_vec());
return bytes;
};
let full_bytes = magnitude.to_be_vec();
let first_nonzero = full_bytes.iter().position(|&b| b != 0).unwrap_or(full_bytes.len());
let significant = &full_bytes[first_nonzero..];
let sig_len = significant.len();
let sign_bit = if is_neg { COMPACT_SIGN_BIT } else { 0 };
if sig_len == 0 {
vec![COMPACT_ZERO | sign_bit]
} else if sig_len <= 255 {
let mut bytes = Vec::with_capacity(2 + sig_len);
bytes.push(COMPACT_SMALL | sign_bit);
bytes.push(sig_len as u8);
bytes.extend_from_slice(significant);
bytes
} else if sig_len <= 65535 {
let mut bytes = Vec::with_capacity(3 + sig_len);
bytes.push(COMPACT_MEDIUM | sign_bit);
bytes.extend_from_slice(&(sig_len as u16).to_be_bytes());
bytes.extend_from_slice(significant);
bytes
} else {
let mut bytes = Vec::with_capacity(1 + full_bytes.len());
bytes.push(COMPACT_FULL | sign_bit);
bytes.extend_from_slice(&full_bytes);
bytes
}
}
pub fn from_compact_bytes(bytes: &[u8]) -> Result<(Self, usize), OverflowDetected> {
if bytes.is_empty() {
return Err(OverflowDetected::InvalidInput);
}
let flags = bytes[0];
let is_neg = (flags & COMPACT_SIGN_BIT) != 0;
let size_class = flags & 0b110;
let magnitude = |payload: &[u8], sig_len: usize| -> Self {
let mut full = vec![0u8; S::BYTES];
let offset = S::BYTES.saturating_sub(sig_len);
let copy_len = sig_len.min(S::BYTES);
let src_offset = sig_len.saturating_sub(S::BYTES);
full[offset..offset + copy_len].copy_from_slice(&payload[src_offset..src_offset + copy_len]);
Self::from_raw(S::from_be_slice(&full))
};
let signed = |val: Self| if is_neg { -val } else { val };
match size_class {
COMPACT_ZERO => Ok((Self::ZERO, 1)),
COMPACT_SMALL => {
if bytes.len() < 2 {
return Err(OverflowDetected::InvalidInput);
}
let sig_len = bytes[1] as usize;
if bytes.len() < 2 + sig_len {
return Err(OverflowDetected::InvalidInput);
}
Ok((signed(magnitude(&bytes[2..2 + sig_len], sig_len)), 2 + sig_len))
}
COMPACT_MEDIUM => {
if bytes.len() < 3 {
return Err(OverflowDetected::InvalidInput);
}
let sig_len = u16::from_be_bytes(bytes[1..3].try_into().unwrap()) as usize;
if bytes.len() < 3 + sig_len {
return Err(OverflowDetected::InvalidInput);
}
Ok((signed(magnitude(&bytes[3..3 + sig_len], sig_len)), 3 + sig_len))
}
_ => {
if bytes.len() < 1 + S::BYTES {
return Err(OverflowDetected::InvalidInput);
}
Ok((signed(Self::from_raw(S::from_be_slice(&bytes[1..1 + S::BYTES]))), 1 + S::BYTES))
}
}
}
}
impl<S: Storage, const F: u32> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
pub fn to_compact_bytes(&self) -> Vec<u8> {
let n = self.len();
let mut bytes = Vec::new();
bytes.extend_from_slice(&(n as u32).to_be_bytes());
for i in 0..n {
bytes.extend_from_slice(&self[i].to_compact_bytes());
}
bytes
}
pub fn from_compact_bytes(bytes: &[u8]) -> Result<(Self, usize), OverflowDetected> {
if bytes.len() < 4 {
return Err(OverflowDetected::InvalidInput);
}
let n = u32::from_be_bytes(bytes[0..4].try_into().unwrap()) as usize;
let mut data = Vec::with_capacity(n);
let mut pos = 4;
for _ in 0..n {
let (val, consumed) = Fixed::from_compact_bytes(&bytes[pos..])?;
data.push(val);
pos += consumed;
}
Ok((FixedVector::from_slice(&data), pos))
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use super::*;
use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::marker::PhantomData;
macro_rules! bytes_serde {
($ty:ident, $what:expr) => {
impl<S: Storage, const F: u32> Serialize for $ty<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
fn serialize<Z: Serializer>(&self, serializer: Z) -> Result<Z::Ok, Z::Error> {
serializer.serialize_bytes(&self.to_bytes())
}
}
impl<'de, S: Storage, const F: u32> Deserialize<'de> for $ty<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct V<S, const F: u32>(PhantomData<S>);
impl<'de, S: Storage, const F: u32> Visitor<'de> for V<S, F>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Value = $ty<Fixed<S, F>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str($what)
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
$ty::from_bytes(v).map_err(|_| E::custom(concat!("invalid ", stringify!($ty), " bytes")))
}
fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
self.visit_bytes(&v)
}
fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut v = Vec::with_capacity(seq.size_hint().unwrap_or(0));
while let Some(b) = seq.next_element::<u8>()? {
v.push(b);
}
self.visit_bytes(&v)
}
}
deserializer.deserialize_bytes(V::<S, F>(PhantomData))
}
}
};
}
impl<S: Storage, const F: u32> Serialize for Fixed<S, F>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
fn serialize<Z: Serializer>(&self, serializer: Z) -> Result<Z::Ok, Z::Error> {
serializer.serialize_bytes(&self.to_bytes())
}
}
impl<'de, S: Storage, const F: u32> Deserialize<'de> for Fixed<S, F>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct V<S, const F: u32>(PhantomData<S>);
impl<'de, S: Storage, const F: u32> Visitor<'de> for V<S, F>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Value = Fixed<S, F>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Fixed bytes (format tag + raw BE)")
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
Fixed::from_bytes(v).map_err(|_| E::custom("invalid Fixed bytes"))
}
fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
self.visit_bytes(&v)
}
fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut v = Vec::with_capacity(seq.size_hint().unwrap_or(0));
while let Some(b) = seq.next_element::<u8>()? {
v.push(b);
}
self.visit_bytes(&v)
}
}
deserializer.deserialize_bytes(V::<S, F>(PhantomData))
}
}
bytes_serde!(FixedVector, "FixedVector bytes (len + raw BE)");
bytes_serde!(FixedMatrix, "FixedMatrix bytes (rows, cols + raw BE)");
bytes_serde!(Tensor, "Tensor bytes (rank, shape + raw BE)");
bytes_serde!(ManifoldPoint, "ManifoldPoint bytes (tag, params + vector)");
}