Skip to content

Commit

Permalink
Prep for borsh support
Browse files Browse the repository at this point in the history
  • Loading branch information
novacrazy committed Nov 21, 2024
1 parent 4b32009 commit 8fdc713
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 3 deletions.
10 changes: 7 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,10 @@ typed-builder = { version = "0.20", optional = true }
schemars = { version = "1.0.0-alpha.14", optional = true, features = ["triomphe01", "smol_str03", "thin-vec02"] }
okapi = { version = "0.7.0-rc.1", optional = true }

# Maybe?
# typescript-definitions = { git = "https://github.com/storyscript/typescript-definitions" }

serde_json = { version = "1", optional = true }

borsh = { version = "1", optional = true }

postgres-types = { version = "0.2.1", optional = true }
bytes = { version = "1", optional = true }
rusqlite = { version = "0.32.0", optional = true }
Expand Down Expand Up @@ -92,6 +91,8 @@ std = ["rkyv?/std", "timestamp/std", "thiserror/std"]

rkyv = ["dep:rkyv", "timestamp/rkyv_08", "snowflake/rkyv", "rkyv_rpc"]

borsh = ["dep:borsh", "snowflake/borsh", "timestamp/borsh"]

schema = ["std", "schemars", "okapi", "timestamp/schema"]

pg = ["std", "postgres-types", "bytes", "timestamp/pg", "snowflake/pg"]
Expand Down Expand Up @@ -132,3 +133,6 @@ rand = "0.8.5"

[profile.dev]
debug = 1

[examples.generate_ts_sdk]
required-features = ["ts"]
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ compile_error!("'typed-builder' and 'bon' features are mutually exclusive");
#[macro_use]
extern crate serde;

#[cfg(feature = "borsh")]
#[macro_use]
extern crate borsh;

#[macro_use]
extern crate bitflags_serde_shim;

Expand Down
56 changes: 56 additions & 0 deletions src/models/nullable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,62 @@ mod impl_serde {
}
}

#[cfg(feature = "borsh")]
mod borsh_impl {
// NOTE: This is manually implemented to maintain a level of compatibility with `Option`,
// which uses 0 and 1 for `None` and `Some`, respectively. Send an Option to be deserialized
// as Nullable using Borsh is therefore valid here. Probably pointless, but still.

use borsh::{de::EnumExt, BorshDeserialize, BorshSerialize};

use super::Nullable;

impl<T> BorshSerialize for Nullable<T>
where
T: BorshSerialize,
{
#[inline]
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
match self {
Nullable::Undefined => 2u8.serialize(writer),
Nullable::Null => 0u8.serialize(writer),
Nullable::Some(value) => {
1u8.serialize(writer)?;
value.serialize(writer)
}
}
}
}

impl<T> BorshDeserialize for Nullable<T>
where
T: BorshDeserialize,
{
#[inline]
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
let tag: u8 = BorshDeserialize::deserialize_reader(reader)?;
Self::deserialize_variant(reader, tag)
}
}

impl<T> EnumExt for Nullable<T>
where
T: BorshDeserialize,
{
fn deserialize_variant<R: std::io::Read>(reader: &mut R, tag: u8) -> std::io::Result<Self> {
match tag {
0 => Ok(Nullable::Null),
1 => Ok(Nullable::Some(T::deserialize_reader(reader)?)),
2 => Ok(Nullable::Undefined),
_ => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Invalid tag: {tag}"),
)),
}
}
}
}

#[cfg(feature = "rusqlite")]
mod rusqlite_impl {
use super::Nullable;
Expand Down
89 changes: 89 additions & 0 deletions src/models/util/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ macro_rules! bitflags2 {
}
}

#[cfg(feature = "borsh")]
const _: () = {
use borsh::{BorshDeserialize, BorshSerialize};

impl BorshSerialize for $BitFlags {
#[inline(always)]
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
self.bits().serialize(writer)
}
}

impl BorshDeserialize for $BitFlags {
#[inline(always)]
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
Ok(Self::from_bits_truncate(<$T as BorshDeserialize>::deserialize_reader(reader)?))
}
}
};

#[cfg(feature = "ts")]
const _: () = {
use ts_bindgen::{Discriminator, TypeScriptDef, TypeScriptType};
Expand Down Expand Up @@ -161,6 +180,44 @@ macro_rules! impl_rkyv_for_bitflags {
}
}

macro_rules! borsh_enum {
(
$(#[$meta:meta])*
$vis:vis enum $name:ident: $repr:ty $(= $unknown:ident)? {
$($(#[$variant_meta:meta])* $code:literal = $variant:ident,)*
}
) => {
const _: () = {
use borsh::{BorshDeserialize, BorshSerialize};

impl BorshSerialize for $name {
#[inline(always)]
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
(*self as $repr).serialize(writer)
}
}

impl BorshDeserialize for $name {
#[inline(always)]
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
let code = <$repr as BorshDeserialize>::deserialize_reader(reader)?;

match code {
$($code => Ok($name::$variant),)*
$(_ => Ok($name::$unknown),)?

#[allow(unreachable_patterns)]
_ => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("invalid enum code: {code}")
)),
}
}
}
};
};
}

#[cfg(feature = "rkyv")]
macro_rules! enum_codes {
(
Expand All @@ -175,6 +232,14 @@ macro_rules! enum_codes {
$($(#[$variant_meta])* $code = $variant,)*
}
}

#[cfg(feature = "borsh")]
borsh_enum! {
$(#[$meta])*
$vis enum $name: $repr $(= $unknown)? {
$($(#[$variant_meta])* $code = $variant,)*
}
}
};
}

Expand All @@ -191,6 +256,14 @@ macro_rules! enum_codes {
$vis enum $name {
$($(#[$variant_meta])* $variant = $code,)*
}

#[cfg(feature = "borsh")]
borsh_enum! {
$(#[$meta])*
$vis enum $name: $repr $(= $unknown)? {
$($(#[$variant_meta])* $code = $variant,)*
}
}
};
}

Expand All @@ -210,6 +283,14 @@ macro_rules! decl_enum {
$($(#[$variant_meta])* $code = $variant,)*
}
}

#[cfg(feature = "borsh")]
borsh_enum! {
$(#[$meta])*
$vis enum $name: $repr {
$($(#[$variant_meta])* $code = $variant,)*
}
}
};
}

Expand All @@ -227,6 +308,14 @@ macro_rules! decl_enum {
$vis enum $name {
$($(#[$variant_meta])* $variant = $code,)*
}

#[cfg(feature = "borsh")]
borsh_enum! {
$(#[$meta])*
$vis enum $name: $repr {
$($(#[$variant_meta])* $code = $variant,)*
}
}
};
}

Expand Down

0 comments on commit 8fdc713

Please sign in to comment.