From 8368ca461aca09a465e0b92819cae34e0af6d47b Mon Sep 17 00:00:00 2001 From: John Smith Date: Mon, 24 Apr 2023 21:24:40 -0400 Subject: [PATCH] rangesetblaze --- Cargo.lock | 21 +++++ veilid-core/Cargo.toml | 1 + .../src/veilid_api/serialize_helpers/mod.rs | 37 ++++++++ .../serialize_helpers/rkyv_enum_set.rs | 53 +++++++++++ .../serialize_helpers/rkyv_range_set_blaze.rs | 73 ++++++++++++++ .../serialize_helpers/serialize_arc.rs | 12 +++ .../serialize_json.rs} | 94 ------------------- .../serialize_range_set_blaze.rs | 60 ++++++++++++ 8 files changed, 257 insertions(+), 94 deletions(-) create mode 100644 veilid-core/src/veilid_api/serialize_helpers/mod.rs create mode 100644 veilid-core/src/veilid_api/serialize_helpers/rkyv_enum_set.rs create mode 100644 veilid-core/src/veilid_api/serialize_helpers/rkyv_range_set_blaze.rs create mode 100644 veilid-core/src/veilid_api/serialize_helpers/serialize_arc.rs rename veilid-core/src/veilid_api/{serialize_helpers.rs => serialize_helpers/serialize_json.rs} (54%) create mode 100644 veilid-core/src/veilid_api/serialize_helpers/serialize_range_set_blaze.rs diff --git a/Cargo.lock b/Cargo.lock index 65a1d656..db294371 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2150,6 +2150,12 @@ dependencies = [ "slab", ] +[[package]] +name = "gen_ops" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f41347f4fa32183c2549b86daf6b6b12a26029a77463e25358f7287580b088b" + [[package]] name = "generic-array" version = "0.12.4" @@ -4245,6 +4251,20 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "range-set-blaze" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e139f0c5edf89edb65753e67eaf8e6031de21ea59f84cb63e0cfb36aaf80e6d0" +dependencies = [ + "gen_ops", + "itertools", + "num-integer", + "num-traits", + "rand 0.8.5", + "thiserror", +] + [[package]] name = "raw-window-handle" version = "0.5.2" @@ -6064,6 +6084,7 @@ dependencies = [ "paranoid-android", "parking_lot 0.12.1", "rand 0.7.3", + "range-set-blaze", "rkyv", "rtnetlink", "rusqlite", diff --git a/veilid-core/Cargo.toml b/veilid-core/Cargo.toml index e7e4f362..8df5b347 100644 --- a/veilid-core/Cargo.toml +++ b/veilid-core/Cargo.toml @@ -69,6 +69,7 @@ keyvaluedb = { path = "../external/keyvaluedb/keyvaluedb" } rkyv = { version = "^0", default_features = false, features = ["std", "alloc", "strict", "size_32", "validation"] } data-encoding = { version = "^2" } weak-table = "0.3.2" +range-set-blaze = "0.1.4" # Dependencies for native builds only # Linux, Windows, Mac, iOS, Android diff --git a/veilid-core/src/veilid_api/serialize_helpers/mod.rs b/veilid-core/src/veilid_api/serialize_helpers/mod.rs new file mode 100644 index 00000000..edd6c968 --- /dev/null +++ b/veilid-core/src/veilid_api/serialize_helpers/mod.rs @@ -0,0 +1,37 @@ +mod rkyv_enum_set; +mod rkyv_range_set_blaze; +pub mod serialize_arc; +pub mod serialize_range_set_blaze; +mod serialize_json; + +use super::*; +use core::fmt::Debug; + +pub use rkyv_enum_set::*; +pub use rkyv_range_set_blaze::*; +pub use serialize_json::*; + +pub fn to_rkyv(v: &T) -> EyreResult> +where + T: RkyvSerialize>, +{ + Ok(rkyv::to_bytes::(v) + .wrap_err("failed to freeze object")? + .to_vec()) +} + +pub fn from_rkyv(v: Vec) -> EyreResult +where + T: RkyvArchive, + ::Archived: + for<'t> CheckBytes>, + ::Archived: + rkyv::Deserialize, +{ + match rkyv::from_bytes::(&v) { + Ok(v) => Ok(v), + Err(e) => { + bail!("failed to deserialize frozen object: {}", e); + } + } +} diff --git a/veilid-core/src/veilid_api/serialize_helpers/rkyv_enum_set.rs b/veilid-core/src/veilid_api/serialize_helpers/rkyv_enum_set.rs new file mode 100644 index 00000000..a3422b48 --- /dev/null +++ b/veilid-core/src/veilid_api/serialize_helpers/rkyv_enum_set.rs @@ -0,0 +1,53 @@ +use super::*; + +pub struct RkyvEnumSet; + +impl rkyv::with::ArchiveWith> for RkyvEnumSet +where + T: EnumSetType + EnumSetTypeWithRepr, + ::Repr: rkyv::Archive, +{ + type Archived = rkyv::Archived<::Repr>; + type Resolver = rkyv::Resolver<::Repr>; + + #[inline] + unsafe fn resolve_with( + field: &EnumSet, + pos: usize, + resolver: Self::Resolver, + out: *mut Self::Archived, + ) { + let r = field.as_repr(); + r.resolve(pos, resolver, out); + } +} + +impl rkyv::with::SerializeWith, S> for RkyvEnumSet +where + S: rkyv::Fallible + ?Sized, + T: EnumSetType + EnumSetTypeWithRepr, + ::Repr: rkyv::Serialize, +{ + fn serialize_with(field: &EnumSet, serializer: &mut S) -> Result { + let r = field.as_repr(); + r.serialize(serializer) + } +} + +impl + rkyv::with::DeserializeWith::Repr>, EnumSet, D> + for RkyvEnumSet +where + D: rkyv::Fallible + ?Sized, + T: EnumSetType + EnumSetTypeWithRepr, + ::Repr: rkyv::Archive, + rkyv::Archived<::Repr>: + rkyv::Deserialize<::Repr, D>, +{ + fn deserialize_with( + field: &rkyv::Archived<::Repr>, + deserializer: &mut D, + ) -> Result, D::Error> { + Ok(EnumSet::::from_repr(field.deserialize(deserializer)?)) + } +} diff --git a/veilid-core/src/veilid_api/serialize_helpers/rkyv_range_set_blaze.rs b/veilid-core/src/veilid_api/serialize_helpers/rkyv_range_set_blaze.rs new file mode 100644 index 00000000..1acc20f6 --- /dev/null +++ b/veilid-core/src/veilid_api/serialize_helpers/rkyv_range_set_blaze.rs @@ -0,0 +1,73 @@ +use super::*; + +use range_set_blaze::*; + +pub struct RkyvRangeSetBlaze; + +impl rkyv::with::ArchiveWith> for RkyvRangeSetBlaze +where + T: rkyv::Archive + Integer, +{ + type Archived = rkyv::Archived>; + type Resolver = rkyv::Resolver>; + + #[inline] + unsafe fn resolve_with( + field: &RangeSetBlaze, + pos: usize, + resolver: Self::Resolver, + out: *mut Self::Archived, + ) { + let mut r = Vec::::with_capacity(field.ranges_len() * 2); + for range in field.ranges() { + r.push(*range.start()); + r.push(*range.end()); + } + r.resolve(pos, resolver, out); + } +} + +impl rkyv::with::SerializeWith, S> for RkyvRangeSetBlaze +where + S: rkyv::Fallible + ?Sized, + Vec: rkyv::Serialize, + T: rkyv::Archive + Integer, +{ + fn serialize_with( + field: &RangeSetBlaze, + serializer: &mut S, + ) -> Result { + let mut r = Vec::::with_capacity(field.ranges_len() * 2); + for range in field.ranges() { + r.push(*range.start()); + r.push(*range.end()); + } + r.serialize(serializer) + } +} + +impl rkyv::with::DeserializeWith>, RangeSetBlaze, D> + for RkyvRangeSetBlaze +where + D: rkyv::Fallible + ?Sized, + T: rkyv::Archive + Integer, + rkyv::Archived: rkyv::Deserialize, + D::Error: From, +{ + fn deserialize_with( + field: &rkyv::Archived>, + deserializer: &mut D, + ) -> Result, D::Error> { + let mut out = RangeSetBlaze::::new(); + if field.len() % 2 == 1 { + return Err("invalid range set length".to_owned().into()); + } + let f = field.as_slice(); + for i in 0..field.len() / 2 { + let l: T = f[i].deserialize(deserializer)?; + let u: T = f[i + 1].deserialize(deserializer)?; + out.ranges_insert(l..=u); + } + Ok(out) + } +} diff --git a/veilid-core/src/veilid_api/serialize_helpers/serialize_arc.rs b/veilid-core/src/veilid_api/serialize_helpers/serialize_arc.rs new file mode 100644 index 00000000..cf8097b2 --- /dev/null +++ b/veilid-core/src/veilid_api/serialize_helpers/serialize_arc.rs @@ -0,0 +1,12 @@ +use alloc::sync::Arc; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +pub fn serialize(v: &Arc, s: S) -> Result { + T::serialize(v.as_ref(), s) +} + +pub fn deserialize<'de, T: Deserialize<'de>, D: Deserializer<'de>>( + d: D, +) -> Result, D::Error> { + Ok(Arc::new(T::deserialize(d)?)) +} diff --git a/veilid-core/src/veilid_api/serialize_helpers.rs b/veilid-core/src/veilid_api/serialize_helpers/serialize_json.rs similarity index 54% rename from veilid-core/src/veilid_api/serialize_helpers.rs rename to veilid-core/src/veilid_api/serialize_helpers/serialize_json.rs index e0ee3788..39494fd4 100644 --- a/veilid-core/src/veilid_api/serialize_helpers.rs +++ b/veilid-core/src/veilid_api/serialize_helpers/serialize_json.rs @@ -1,7 +1,5 @@ use super::*; -use core::fmt::Debug; - // Don't trace these functions as they are used in the transfer of API logs, which will recurse! // #[instrument(level = "trace", ret, err)] @@ -114,95 +112,3 @@ pub mod opt_json_as_string { } } } - -pub mod arc_serialize { - use alloc::sync::Arc; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - pub fn serialize(v: &Arc, s: S) -> Result { - T::serialize(v.as_ref(), s) - } - - pub fn deserialize<'de, T: Deserialize<'de>, D: Deserializer<'de>>( - d: D, - ) -> Result, D::Error> { - Ok(Arc::new(T::deserialize(d)?)) - } -} - -pub fn to_rkyv(v: &T) -> EyreResult> -where - T: RkyvSerialize>, -{ - Ok(rkyv::to_bytes::(v) - .wrap_err("failed to freeze object")? - .to_vec()) -} - -pub fn from_rkyv(v: Vec) -> EyreResult -where - T: RkyvArchive, - ::Archived: - for<'t> CheckBytes>, - ::Archived: - rkyv::Deserialize, -{ - match rkyv::from_bytes::(&v) { - Ok(v) => Ok(v), - Err(e) => { - bail!("failed to deserialize frozen object: {}", e); - } - } -} - -pub struct RkyvEnumSet; - -impl rkyv::with::ArchiveWith> for RkyvEnumSet -where - T: EnumSetType + EnumSetTypeWithRepr, - ::Repr: rkyv::Archive, -{ - type Archived = rkyv::Archived<::Repr>; - type Resolver = rkyv::Resolver<::Repr>; - - #[inline] - unsafe fn resolve_with( - field: &EnumSet, - pos: usize, - resolver: Self::Resolver, - out: *mut Self::Archived, - ) { - let r = field.as_repr(); - r.resolve(pos, resolver, out); - } -} - -impl rkyv::with::SerializeWith, S> for RkyvEnumSet -where - S: rkyv::Fallible + ?Sized, - T: EnumSetType + EnumSetTypeWithRepr, - ::Repr: rkyv::Serialize, -{ - fn serialize_with(field: &EnumSet, serializer: &mut S) -> Result { - let r = field.as_repr(); - r.serialize(serializer) - } -} - -impl - rkyv::with::DeserializeWith::Repr>, EnumSet, D> - for RkyvEnumSet -where - D: rkyv::Fallible + ?Sized, - T: EnumSetType + EnumSetTypeWithRepr, - ::Repr: rkyv::Archive, - rkyv::Archived<::Repr>: - rkyv::Deserialize<::Repr, D>, -{ - fn deserialize_with( - field: &rkyv::Archived<::Repr>, - deserializer: &mut D, - ) -> Result, D::Error> { - Ok(EnumSet::::from_repr(field.deserialize(deserializer)?)) - } -} diff --git a/veilid-core/src/veilid_api/serialize_helpers/serialize_range_set_blaze.rs b/veilid-core/src/veilid_api/serialize_helpers/serialize_range_set_blaze.rs new file mode 100644 index 00000000..5ef5fa46 --- /dev/null +++ b/veilid-core/src/veilid_api/serialize_helpers/serialize_range_set_blaze.rs @@ -0,0 +1,60 @@ +use core::fmt; +use core::marker::PhantomData; +use range_set_blaze::*; +use serde::{ + de::SeqAccess, de::Visitor, ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer, +}; + +pub fn serialize( + v: &RangeSetBlaze, + s: S, +) -> Result { + let cnt = v.ranges_len() * 2; + let mut seq = s.serialize_seq(Some(cnt))?; + for range in v.ranges() { + seq.serialize_element(range.start())?; + seq.serialize_element(range.end())?; + } + seq.end() +} + +pub fn deserialize<'de, T: Integer + Deserialize<'de>, D: Deserializer<'de>>( + d: D, +) -> Result, D::Error> { + struct RangeSetBlazeVisitor { + marker: PhantomData, + } + + impl<'de, T> Visitor<'de> for RangeSetBlazeVisitor + where + T: Deserialize<'de> + Integer, + { + type Value = RangeSetBlaze; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a RangeSetBlaze") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut values = RangeSetBlaze::::new(); + + while let Some(start) = seq.next_element()? { + let Some(end) = seq.next_element()? else { + break; + }; + values.ranges_insert(start..=end); + } + + Ok(values) + } + } + + let visitor = RangeSetBlazeVisitor { + marker: PhantomData, + }; + + d.deserialize_seq(visitor) +}