astro-float icon indicating copy to clipboard operation
astro-float copied to clipboard

rkyv support

Open HaHa421 opened this issue 3 months ago • 4 comments

Would it be relatively straightforward to add rkyv support as a feature?

HaHa421 avatar Sep 01 '25 06:09 HaHa421

with rkyv 0.8.11, it seems to be straithforward , except for Sign where I used https://github.com/rkyv/rkyv/issues/482#issuecomment-2351618161 as follow:

#[cfg(feature = "rkyv")]
mod rkyv_impl {
  use super::Sign;
  use rkyv::{
    bytecheck::{CheckBytes, InvalidEnumDiscriminantError, Verify},
    primitive::ArchivedI16,
    rancor::{fail, Fallible, Source},
    traits::NoUndef,
    Archive, Deserialize, Place, Portable, Serialize,
  };
  // Hand-written archived enum
  #[derive(CheckBytes, Portable)]
  #[bytecheck(crate = rkyv::bytecheck, verify)]
  #[repr(C)]
  pub struct ArchivedSign(ArchivedI16);

  // Implementation detail: `ArchivedMyEnum` has no undef bytes
  unsafe impl NoUndef for ArchivedSign {}

  impl ArchivedSign {
      // Internal fallible conversion back to the original enum
      fn try_to_native(&self) -> Option<Sign> {
          Some(match self.0.to_native() {
              -1 => Sign::Neg,
              1 => Sign::Pos,
              _ => return None,
          })
      }

      // Public infallible conversion back to the original enum
      pub fn to_native(&self) -> Sign {
          unsafe { self.try_to_native().unwrap_unchecked() }
      }
  }

  unsafe impl<C: Fallible + ?Sized> Verify<C> for ArchivedSign
  where
      C::Error: Source,
  {
      // verify runs after all of the fields have been checked
      fn verify(&self, _: &mut C) -> Result<(), C::Error> {
          // Use the internal conversion to try to convert back
          if self.try_to_native().is_none() {
              // Return an error if it fails (i.e. the discriminant did not match
              // any valid discriminants)
              fail!(InvalidEnumDiscriminantError {
                  enum_name: "ArchivedSign",
                  invalid_discriminant: self.0.to_native(),
              })
          }
          Ok(())
      }
  }

  impl Archive for Sign {
      type Archived = ArchivedSign;
      type Resolver = ();

      fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
          // Convert Sign -> i16 -> ArchivedI16 and write to `out`
          out.write(ArchivedSign((*self as i16).into()));
      }
  }

  // Serialization is a no-op because there's no out-of-line data
  impl<S: Fallible + ?Sized> Serialize<S> for Sign {
      fn serialize(&self, _: &mut S) -> Result<Self::Resolver, <S as Fallible>::Error> {
          Ok(())
      }
  }

  // Deserialization just calls the public conversion and returns the result
  impl<D: Fallible + ?Sized> Deserialize<Sign, D> for ArchivedSign {
      fn deserialize(&self, _: &mut D) -> Result<Sign, <D as Fallible>::Error> {
          Ok(self.to_native())
      }
  }
}
#[cfg(feature = "rkyv")]
pub use rkyv_impl::*;

and #[cfg_attr(feature = "rkyv", derive(Archive, Serialize, Deserialize))] for other types

HaHa421 avatar Sep 01 '25 08:09 HaHa421

Can't tell if it would be straightforward to add this. What is the use-case for serializing floats with rkyv?

stencillogic avatar Sep 04 '25 16:09 stencillogic

I'm working on a client-server framework that uses rkyv for message exchange, and BigFloat is part of some messages. I patched astro-float to support serialization with rkyv so it integrates cleanly into the system. Just wanted to check if you'd be open to formalizing support for this use case. Happy to share the patch or open a PR if that helps.

HaHa421 avatar Sep 04 '25 17:09 HaHa421

Thank you for the suggestion. I am not familiar with rkyv, but you are welcome to open a PR. I hope I will look at it at some point.

stencillogic avatar Sep 04 '25 17:09 stencillogic