From caf6e744502d203c7917410a5ecc86e6d6e091ef Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Thu, 6 Nov 2025 16:31:30 -0600 Subject: [PATCH] don't use facet, just make the macro more readable + nightly declarative macros --- flake.lock | 6 +- service/Cargo.lock | 257 ++------- service/Cargo.toml | 2 - service/rust-toolchain | 2 +- service/src/lib/domain/ci/models/repo.rs | 12 +- service/src/lib/mod.rs | 2 + service/src/lib/outbound/db_custom/mod.rs | 71 +-- .../src/lib/outbound/db_custom/write_set.rs | 545 +++++++----------- 8 files changed, 301 insertions(+), 596 deletions(-) diff --git a/flake.lock b/flake.lock index 077c116..183662e 100644 --- a/flake.lock +++ b/flake.lock @@ -62,11 +62,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1762223900, - "narHash": "sha256-caxpESVH71mdrdihYvQZ9rTZPZqW0GyEG9un7MgpyRM=", + "lastModified": 1762396738, + "narHash": "sha256-BarSecuxtzp1boERdABLkkoxQTi6s/V33lJwUbWLrLY=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "cfe1598d69a42a5edb204770e71b8df77efef2c3", + "rev": "c63598992afd54d215d54f2b764adc0484c2b159", "type": "github" }, "original": { diff --git a/service/Cargo.lock b/service/Cargo.lock index 33fc490..1516f64 100644 --- a/service/Cargo.lock +++ b/service/Cargo.lock @@ -10,8 +10,6 @@ dependencies = [ "axum", "bincode", "dotenv", - "facet", - "field_types", "reqwest", "serde", "serde_json", @@ -32,9 +30,9 @@ version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -140,12 +138,6 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.10.1" @@ -219,9 +211,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -255,86 +247,12 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "facet" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49184c644e74dd0e899d21144285e92598d682845c8ef0d13da05f1c67c2bcc5" -dependencies = [ - "facet-core", - "facet-macros", - "facet-reflect", - "static_assertions", -] - -[[package]] -name = "facet-core" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e09a4180d0a78a9e444cb57ea57b2c1d65ab140e53e35535b76713454a8e158e" -dependencies = [ - "bitflags 2.10.0", - "impls", -] - -[[package]] -name = "facet-macros" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bfcaf327d2f5d94bc208e81d625acfdab871f47f9915a34929335762d4d312" -dependencies = [ - "facet-core", - "facet-macros-emit", -] - -[[package]] -name = "facet-macros-emit" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084b862aa27ccade8c0d249b57960975611d1f9dfcd3c8c42a25aaa7d14cd1c2" -dependencies = [ - "facet-macros-parse", - "quote 1.0.41", -] - -[[package]] -name = "facet-macros-parse" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c198c8252d559dff4ef2846662b8ac63496ec4cbe734651a5ffedeefaa8652" -dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "unsynn", -] - -[[package]] -name = "facet-reflect" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91debebf849ca4acf73f14c74dc5642f8b8e1aa823c86cabfa5d0b4825c66323" -dependencies = [ - "bitflags 2.10.0", - "facet-core", -] - [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "field_types" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "152ff4498a8c01b91737676420a1cd84e92724cb610320fdebee6838e4651c9a" -dependencies = [ - "heck", - "quote 0.6.13", - "syn 0.15.44", -] - [[package]] name = "find-msvc-tools" version = "0.1.4" @@ -410,15 +328,6 @@ dependencies = [ "pin-utils", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.14.9" @@ -490,15 +399,6 @@ dependencies = [ "http", ] -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "http" version = "0.2.12" @@ -678,12 +578,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "impls" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a46645bbd70538861a90d0f26c31537cdf1e44aae99a794fb75a664b70951bc" - [[package]] name = "indexmap" version = "2.12.0" @@ -769,12 +663,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "mutants" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0287524726960e07b119cebd01678f852f147742ae0d925e6a520dca956126" - [[package]] name = "native-tls" version = "0.2.14" @@ -819,9 +707,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -863,9 +751,9 @@ version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -895,15 +783,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid", -] - [[package]] name = "proc-macro2" version = "1.0.103" @@ -913,22 +792,13 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - [[package]] name = "quote" version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ - "proc-macro2 1.0.103", + "proc-macro2", ] [[package]] @@ -1068,9 +938,9 @@ version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1120,12 +990,6 @@ dependencies = [ "digest", ] -[[package]] -name = "shadow_counted" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65da48d447333cebe1aadbdd3662f3ba56e76e67f53bc46f3dd5f67c74629d6b" - [[package]] name = "shlex" version = "1.3.0" @@ -1179,31 +1043,14 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid", -] - [[package]] name = "syn" version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", + "proc-macro2", + "quote", "unicode-ident", ] @@ -1219,9 +1066,9 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1273,9 +1120,9 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1310,9 +1157,9 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1422,30 +1269,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - -[[package]] -name = "unsynn" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940603a9e25cf11211cc43b81f4fcad2b8ab4df291ca855f32c40e1ac22d5bc" -dependencies = [ - "fxhash", - "mutants", - "proc-macro2 1.0.103", - "shadow_counted", -] - [[package]] name = "unty" version = "0.0.4" @@ -1544,7 +1367,7 @@ version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ - "quote 1.0.41", + "quote", "wasm-bindgen-macro-support", ] @@ -1555,9 +1378,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ "bumpalo", - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", "wasm-bindgen-shared", ] @@ -1847,9 +1670,9 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", "synstructure", ] @@ -1868,9 +1691,9 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", "synstructure", ] @@ -1902,7 +1725,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ - "proc-macro2 1.0.103", - "quote 1.0.41", - "syn 2.0.108", + "proc-macro2", + "quote", + "syn", ] diff --git a/service/Cargo.toml b/service/Cargo.toml index 4cbf244..1c68dfc 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -15,8 +15,6 @@ anyhow = "1.0.100" axum = { version = "0.6.9", features = ["headers"] } bincode = "2.0.1" dotenv = "0.15.0" -facet = { version = "0.31.3", features = ["reflect"] } -field_types = "1.1.0" reqwest = "0.11.14" serde = "1.0.152" serde_json = "1.0.93" diff --git a/service/rust-toolchain b/service/rust-toolchain index 2bf5ad0..9863396 100644 --- a/service/rust-toolchain +++ b/service/rust-toolchain @@ -1 +1 @@ -stable +nightly-2025-11-05 diff --git a/service/src/lib/domain/ci/models/repo.rs b/service/src/lib/domain/ci/models/repo.rs index 024ee37..6140c66 100644 --- a/service/src/lib/domain/ci/models/repo.rs +++ b/service/src/lib/domain/ci/models/repo.rs @@ -41,7 +41,11 @@ impl Storable for DbRepository { } impl Diffable for DbRepository { - fn diff(&self, other: &Self) -> Vec { + fn diff( + &self, + other: &Self, + field_prefix: &str, + ) -> Vec { todo!() } } @@ -89,7 +93,11 @@ impl Storable for Repository { } impl Diffable for Repository { - fn diff(&self, other: &Self) -> Vec + fn diff( + &self, + other: &Self, + field_prefix: &str, + ) -> Vec where Self: Sized, { diff --git a/service/src/lib/mod.rs b/service/src/lib/mod.rs index a65f027..b62500d 100644 --- a/service/src/lib/mod.rs +++ b/service/src/lib/mod.rs @@ -1,3 +1,5 @@ +#![feature(macro_derive)] + pub mod domain; pub mod inbound; pub mod outbound; diff --git a/service/src/lib/outbound/db_custom/mod.rs b/service/src/lib/outbound/db_custom/mod.rs index 304351b..13aa78a 100644 --- a/service/src/lib/outbound/db_custom/mod.rs +++ b/service/src/lib/outbound/db_custom/mod.rs @@ -7,8 +7,6 @@ use std::{ sync::{Arc, Mutex}, }; -use facet::Facet; - use crate::outbound::db_custom::write_set::{Diffable, Storable, Write, WriteOperation, WriteSet}; #[derive( @@ -22,7 +20,7 @@ impl From for TransactionId { } } -#[derive(Debug, Copy, Clone, facet::Facet)] +#[derive(Debug, Copy, Clone)] pub struct Id { id: u64, _type: PhantomData, @@ -37,6 +35,15 @@ impl Id { } } +impl From<&TypelessId> for Id { + fn from(value: &TypelessId) -> Self { + Self { + id: (*value).into(), + _type: PhantomData, + } + } +} + impl bincode::Encode for Id { fn encode( &self, @@ -89,6 +96,12 @@ impl std::hash::Hash for Id { #[derive(Default, Copy, Clone, PartialEq, Eq, Hash, Debug, bincode::Encode, bincode::Decode)] struct TypelessId(u64); +impl From for u64 { + fn from(value: TypelessId) -> Self { + value.0 + } +} + impl From> for TypelessId { fn from(id: Id) -> Self { Self(id.id) @@ -394,7 +407,7 @@ impl<'a> PendingTransaction<'a> { self.accessor.get(id, self.timestamp) } - pub fn get_field Facet<'facet> + Clone + 'static>( + pub fn get_field( &mut self, id: Id, field: &'static str, @@ -466,16 +479,6 @@ pub enum Value { } impl Value { - fn size(&self) -> Option { - match self { - Value::String(_) | Value::Array(_) => None, - - Value::Int(_) => Some(size_of::()), - Value::Float(_) => Some(size_of::()), - Value::Bool(_) => Some(size_of::()), - } - } - fn as_string(&self) -> Option<&String> { match self { Value::String(s) => Some(s), @@ -514,26 +517,26 @@ mod tests { use std::collections::HashSet; use bincode::{Decode, Encode}; - use facet::Facet; use super::*; + use crate::Storable; - #[derive(Debug, Clone, Encode, Decode, Facet)] + #[derive(Debug, Clone, Storable, Encode, Decode)] struct MyTestData { name: Name, age: i64, ff: String, - //contacts: HashSet>, + contacts: HashSet>, } - #[derive(Debug, Clone, Encode, Decode, Facet)] + #[derive(Debug, Clone, Storable, Encode, Decode)] struct Name { nest: SuperNested, first: String, last: String, } - #[derive(Debug, Clone, Encode, Decode, Facet)] + #[derive(Debug, Clone, Storable, Encode, Decode)] struct SuperNested { i_am_a_really_nested_field: i64, } @@ -561,7 +564,7 @@ mod tests { }, }, age: 1337, - //contacts: vec![Id::new(1)].into_iter().collect(), + contacts: vec![Id::new(1)].into_iter().collect(), }; println!("initial state: {:#?}", accessor.db.lock().unwrap()); @@ -580,7 +583,7 @@ mod tests { }, }, age: 3000, - //contacts: vec![Id::new(1)].into_iter().collect(), + contacts: vec![Id::new(1)].into_iter().collect(), }, ); }); @@ -588,16 +591,16 @@ mod tests { let cloned_accessor = accessor.clone(); let handle = std::thread::spawn(move || { cloned_accessor.transact(|t| { - //let Some(Value::String(last_name_of_oldy)) = - // t.get_field(Id::::new(2), "name.last") - //else { - // panic!("expected a string") - //}; - // + let Some(Value::String(last_name_of_oldy)) = + t.get_field(Id::::new(2), "name.last") + else { + panic!("expected a string") + }; + t.modify(Id::::new(1), |mut data| { data.age = 9; data.name.nest.i_am_a_really_nested_field = 99999; - //data.name.last = format!("Gearbox {}", last_name_of_oldy); + data.name.last = format!("Gearbox {}", last_name_of_oldy); data }); }); @@ -618,13 +621,11 @@ mod tests { let oldys_contacts = accessor.transact(|t| { let oldy = t.get(Id::::new(2)).unwrap(); - vec![0] - - //oldy.contacts - // .into_iter() - // .filter_map(|id| t.get(id)) - // .map(|data| format!("{} {}", data.name.first, data.name.last)) - // .collect::>() + oldy.contacts + .into_iter() + .filter_map(|id| t.get(id)) + .map(|data| format!("{} {}", data.name.first, data.name.last)) + .collect::>() }); handle.join().unwrap(); diff --git a/service/src/lib/outbound/db_custom/write_set.rs b/service/src/lib/outbound/db_custom/write_set.rs index 25468c8..e53b1f0 100644 --- a/service/src/lib/outbound/db_custom/write_set.rs +++ b/service/src/lib/outbound/db_custom/write_set.rs @@ -1,15 +1,16 @@ +use std::collections::HashSet; + use bincode::{Decode, Encode}; -use facet::{Facet, Field, PtrConst, Shape}; use crate::outbound::db_custom::{TypelessId, Value}; #[derive(bincode::Encode)] -struct TransactionEntity { +pub struct TransactionEntity { name: String, data: T, } impl TransactionEntity { - fn with(name: impl ToString, data: T) -> Self { + pub fn with(name: impl ToString, data: T) -> Self { Self { name: name.to_string(), data, @@ -25,7 +26,7 @@ pub trait Storable: Diffable + std::fmt::Debug + std::any::Any { where Self: Sized, { - WriteOperation::Partial(self.diff(other).into_iter().map(Into::into).collect()) + WriteOperation::Partial(self.diff(other, "").into_iter().map(Into::into).collect()) } fn apply_partial_write(&mut self, op: &PartialWrite); @@ -40,269 +41,14 @@ pub trait Storable: Diffable + std::fmt::Debug + std::any::Any { } pub trait Diffable { - fn diff(&self, other: &Self) -> Vec + fn diff(&self, other: &Self, field_prefix: &str) -> Vec where Self: Sized; } -struct ShapeVal<'a, 's>(&'a Shape, PtrConst<'a>, &'s str); - -impl<'a, 's> Diffable for ShapeVal<'a, 's> { - fn diff(&self, other: &Self) -> Vec - where - Self: Sized, - { - let mut modifications = vec![]; - - let facet::Type::User(user) = self.0.ty else { - panic!("invalid type"); - }; - - match user { - facet::UserType::Struct(struct_type) => { - //println!("{:#?}", struct_type.fields); - - for field in struct_type.fields { - let field_shape = field.shape(); - //println!("{:#?}", field_shape); - - let (self_field_ptr, other_field_ptr) = unsafe { - let offset = field.offset.try_into().unwrap(); - - let self_ptr: *const u8 = self.1.as_ptr(); - let me_field_ptr = self_ptr.offset(offset); - - let other_ptr: *const u8 = other.1.as_ptr(); - let other_field_ptr = other_ptr.offset(offset); - - let me = PtrConst::new(std::ptr::NonNull::new_unchecked( - me_field_ptr as *mut u8, - )); - let other = PtrConst::new(std::ptr::NonNull::new_unchecked( - other_field_ptr as *mut u8, - )); - - (me, other) - }; - - match field_shape.def { - facet::Def::Undefined => { - let me = ShapeVal( - field_shape, - self_field_ptr, - &format!("{}{}.", self.2, field.name), - ); - let other = ShapeVal( - field_shape, - other_field_ptr, - &format!("{}{}.", self.2, field.name), - ); - - modifications.extend(me.diff(&other).into_iter()); - } - facet::Def::Scalar => { - let partial_eq = field_shape.vtable.partial_eq.unwrap(); - - let are_partially_eq = - unsafe { partial_eq(self_field_ptr, other_field_ptr) }; - - if !are_partially_eq { - //println!("{:#?}", field); - //println!("{:#?}", field_shape); - modifications.push(FieldDiff::of( - format!("{}{}", self.2, field.name), - Value::from_field_value(other, field), - )); - } - } - facet::Def::Map(map_def) => todo!(), - facet::Def::Set(set_def) => {} - facet::Def::List(list_def) => todo!(), - facet::Def::Array(array_def) => todo!(), - facet::Def::NdArray(nd_array_def) => todo!(), - facet::Def::Slice(slice_def) => todo!(), - facet::Def::Option(option_def) => todo!(), - facet::Def::Pointer(pointer_def) => todo!(), - _ => todo!(), - } - } - } - facet::UserType::Enum(enum_type) => todo!(), - facet::UserType::Union(union_type) => panic!("union types are unsupported"), - facet::UserType::Opaque => panic!("opaque types are invalid"), - } - - modifications - } -} - -impl<'a, 's> ShapeVal<'a, 's> { - fn set_field(&self, field_ident: &str, value: Value) { - let mut idents = field_ident.split("."); - let next = idents.next().unwrap(); - - let facet::Type::User(user) = self.0.ty else { - panic!("invalid type"); - }; - - println!("next: {next}"); - - match user { - facet::UserType::Struct(struct_type) => { - if let Some(field) = struct_type.fields.iter().find(|f| f.name == next) { - let field_shape = field.shape(); - match field_shape.ty { - facet::Type::Primitive(primitive_type) => { - let layout = field_shape - .layout - .sized_layout() - .expect("primitive type is sized"); - let primitive_size = layout.size(); - if Some(primitive_size) != value.size() { - panic!("invalid primitive size"); - } - - unsafe { - let self_ptr = self.1.as_byte_ptr() as *mut u8; - let field_ptr = self_ptr.offset(field.offset.try_into().unwrap()); - - match value { - Value::String(_) | Value::Array(_) => { - panic!("String & Array are not primitive types") - } - - Value::Int(value) => { - let r = (field_ptr as *mut i64).as_mut().unwrap(); - println!("value: {value}, r before: {r}"); - *r = value; - println!("r after: {r}"); - } - Value::Float(value) => *(field_ptr as *mut f64) = value, - Value::Bool(value) => *(field_ptr as *mut bool) = value, - } - } - } - facet::Type::Sequence(sequence_type) => todo!(), - facet::Type::User(user_type) => match user_type { - facet::UserType::Struct(struct_type) => { - let field_ptr = unsafe { - let self_ptr = self.1.as_byte_ptr() as *mut u8; - let field_ptr = - self_ptr.offset(field.offset.try_into().unwrap()); - - PtrConst::new(std::ptr::NonNull::new_unchecked(field_ptr)) - }; - let field_val = ShapeVal(field_shape, field_ptr, ""); - - field_val.set_field(&field_ident[(field.name.len() + 1)..], value); - } - facet::UserType::Enum(enum_type) => todo!(), - facet::UserType::Union(union_type) => todo!(), - facet::UserType::Opaque if field_shape.type_identifier == "String" => { - let Value::String(value) = value else { - panic!("got non-string value"); - }; - - let field_ref = unsafe { - let self_ptr = self.1.as_byte_ptr() as *mut u8; - let field_ptr = self_ptr - .offset(field.offset.try_into().unwrap()) - as *mut String; - - field_ptr.as_mut().unwrap() - }; - - *field_ref = value; - } - facet::UserType::Opaque => panic!("unsupported type"), - }, - facet::Type::Pointer(pointer_type) => todo!(), - } - } else { - panic!("couldn't find field: {next}"); - } - } - facet::UserType::Enum(enum_type) => todo!(), - facet::UserType::Union(union_type) => panic!("union types are unsupported"), - facet::UserType::Opaque => panic!("opaque types are invalid"), - } - } -} - -impl Facet<'a> + for<'a> FieldValueRef<'a>> Diffable for T { - fn diff(&self, other: &Self) -> Vec - where - Self: Sized, - { - let (me, other) = unsafe { - let me = ShapeVal( - Self::SHAPE, - PtrConst::new(std::ptr::NonNull::new_unchecked( - self as *const _ as *mut u8, - )), - "", - ); - - let other = ShapeVal( - Self::SHAPE, - PtrConst::new(std::ptr::NonNull::new_unchecked( - other as *const _ as *mut u8, - )), - "", - ); - - (me, other) - }; - - me.diff(&other) - } -} - -impl Facet<'a> + Diffable + Encode + std::fmt::Debug> Storable for T { - fn as_full_write_op(&self) -> WriteOperation - where - Self: Sized, - { - let data = bincode::encode_to_vec( - TransactionEntity::with(Self::SHAPE.type_identifier, self), - bincode::config::standard(), - ) - .expect("encode MUST succeed"); - - WriteOperation::Full(data) - } - - fn apply_partial_write(&mut self, op: &PartialWrite) { - println!("{:#?}", op); - println!("before: {:#?}", self); - let value = Value::from_bytes(&op.data); - self.set_field(&op.field_ident, value); - println!("after: {:#?}", self); - } - - fn set_field(&mut self, field_ident: &str, value: Value) - where - Self: for<'a> Facet<'a> + Sized, - { - let me = unsafe { - ShapeVal( - Self::SHAPE, - PtrConst::new(std::ptr::NonNull::new_unchecked( - self as *const _ as *mut u8, - )), - "", - ) - }; - - me.set_field(field_ident, value); - } - - fn field(&self, field_ident: &str) -> Option - where - Self: for<'a> Facet<'a> + Sized, - { - None - } +pub trait Valuable { + fn update_with_value(&mut self, field_name: &str, value: Value); + fn as_value(&self, field_name: &str) -> Option; } pub struct FieldDiff { @@ -330,79 +76,6 @@ impl From for PartialWrite { } } -trait FieldValueRef<'a> { - fn get_field_value_as_ref(&'a self, field: &Field) -> &'a F { - unsafe { - let container_ptr = self as *const _ as *const u8; - let field_ptr = container_ptr.offset(field.offset.try_into().unwrap()) as *const F; - - field_ptr.as_ref().unwrap() - } - } -} - -impl<'a, T: Facet<'a>> FieldValueRef<'a> for T {} - -impl<'a, 's> FieldValueRef<'a> for ShapeVal<'a, 's> { - fn get_field_value_as_ref(&'a self, field: &Field) -> &'a F { - unsafe { - let container_ptr: *const u8 = self.1.as_ptr(); - let field_ptr = container_ptr.offset(field.offset.try_into().unwrap()) as *const F; - - field_ptr.as_ref().unwrap() - } - } -} - -impl Value { - fn from_field_value<'a, T: FieldValueRef<'a>>(container: &'a T, field: &Field) -> Self { - let shape = field.shape(); - - match shape.ty { - facet::Type::Primitive(primitive_type) => match primitive_type { - facet::PrimitiveType::Boolean => { - Self::Bool(*container.get_field_value_as_ref(field)) - } - facet::PrimitiveType::Numeric(numeric_type) => { - let field_layout = field.shape().layout.sized_layout().unwrap(); - - const I32_SIZE: usize = size_of::(); - const I64_SIZE: usize = size_of::(); - - match (field_layout.size(), numeric_type) { - (I32_SIZE, facet::NumericType::Integer { signed }) if signed => { - Value::Int(*container.get_field_value_as_ref::(field) as i64) - } - (I32_SIZE, facet::NumericType::Integer { .. }) => { - Value::Int(*container.get_field_value_as_ref::(field) as i64) - } - - (I64_SIZE, facet::NumericType::Integer { signed }) if signed => { - Value::Int(*container.get_field_value_as_ref::(field) as i64) - } - (I64_SIZE, facet::NumericType::Integer { .. }) => { - Value::Int(*container.get_field_value_as_ref::(field) as i64) - } - _ => panic!("invalid numeric size"), - } - } - facet::PrimitiveType::Textual(textual_type) => todo!(), - facet::PrimitiveType::Never => todo!(), - }, - - facet::Type::Sequence(sequence_type) => todo!(), - facet::Type::User(user_type) => { - if shape.type_identifier == "String" { - Value::String(container.get_field_value_as_ref::(field).clone()) - } else { - todo!("asdkjhfadsfkdasjhfdssklsadkljfkljasdhfkjlhsdfklsdkfhsd"); - } - } - facet::Type::Pointer(pointer_type) => todo!("alkjhdfklajdhs"), - } - } -} - #[derive(Debug, Default, Encode, Decode)] pub struct WriteSet { // TODO: make an actual set @@ -426,3 +99,203 @@ pub struct PartialWrite { pub(super) field_ident: String, pub(super) data: Vec, } + +impl Valuable for i64 { + fn update_with_value(&mut self, _field_name: &str, value: Value) { + if let Some(value) = value.as_int() { + *self = *value; + } else { + panic!("value is not an i64"); + } + } + + fn as_value(&self, _field_name: &str) -> Option { + Some(Value::Int(*self)) + } +} + +impl Valuable for String { + fn update_with_value(&mut self, _field_name: &str, value: Value) { + if let Some(value) = value.as_string() { + *self = value.clone(); + } else { + panic!("value is not a String"); + } + } + + fn as_value(&self, _field_name: &str) -> Option { + Some(Value::String(self.clone())) + } +} + +impl Valuable for HashSet +where + T: for<'a> From<&'a TypelessId>, + TypelessId: for<'a> From<&'a T>, +{ + fn update_with_value(&mut self, _field_name: &str, value: Value) { + if let Some(value) = value.as_array() { + *self = value.iter().map(Into::into).collect(); + } else { + panic!("value is not a String"); + } + } + + fn as_value(&self, _field_name: &str) -> Option { + Some(Value::Array(self.iter().map(|id| id.into()).collect())) + } +} + +impl Diffable for i64 { + fn diff(&self, other: &Self, field_prefix: &str) -> Vec + where + Self: Sized, + { + if *self != *other { + vec![FieldDiff::of(field_prefix, Value::Int(*other))] + } else { + vec![] + } + } +} + +impl Diffable for String { + fn diff(&self, other: &Self, field_prefix: &str) -> Vec + where + Self: Sized, + { + if *self != *other { + vec![FieldDiff::of(field_prefix, Value::String(other.clone()))] + } else { + vec![] + } + } +} + +impl Diffable for HashSet +where + TypelessId: for<'a> From<&'a T>, +{ + fn diff(&self, other: &Self, field_prefix: &str) -> Vec + where + Self: Sized, + { + let diff = self.difference(other); + if diff.count() > 0 { + vec![FieldDiff::of( + field_prefix, + Value::Array(other.iter().map(|id| id.into()).collect()), + )] + } else { + vec![] + } + } +} + +#[macro_export] +macro_rules! Storable { + derive() { + struct $n:ident { + $( + $field_name:ident: $field_type:ty, + )* + } + } => { + impl $crate::outbound::db_custom::write_set::Valuable for $n { + fn update_with_value(&mut self, field_name: &str, value: Value) { + self.set_field(field_name, value); + } + + fn as_value(&self, field_name: &str) -> Option { + self.field(field_name) + } + } + + impl Storable for $n { + fn as_full_write_op(&self) -> WriteOperation + where + Self: Sized + { + use $crate::outbound::db_custom::write_set::TransactionEntity; + + let data = + ::bincode::encode_to_vec(TransactionEntity::with(stringify!($n), self), ::bincode::config::standard()) + .expect("encode MUST succeed"); + + WriteOperation::Full(data) + } + + fn apply_partial_write(&mut self, op: &$crate::outbound::db_custom::write_set::PartialWrite) + where + Self: Sized, + { + let value = Value::from_bytes(&op.data); + self.set_field(&op.field_ident, value); + } + + fn set_field(&mut self, field_ident: &str, value: Value) + where + Self: Sized + { + use $crate::outbound::db_custom::write_set::Valuable; + + let mut idents = field_ident.split("."); + let next = idents.next().unwrap(); + + match next { + $( + stringify!($field_name) => { + self.$field_name.update_with_value(&field_ident[(next.len()+1)..], value); + } + ),* + + _ => panic!("set_field: invalid field '{next}'"), + } + } + + fn field(&self, field_ident: &str) -> Option + where + Self: Sized + { + use $crate::outbound::db_custom::write_set::Valuable; + + let mut idents = field_ident.split("."); + let next = idents.next().unwrap(); + + let nested_field_name = if next.len()+1 >= field_ident.len() { + "" + } else { + &field_ident[(next.len()+1)..] + }; + + match next { + $( + stringify!($field_name) => { + println!("{} - {}", stringify!($field_name), field_ident); + self.$field_name.as_value(nested_field_name) + } + ),* + + _ => panic!("set_field: invalid field '{next}'"), + } + } + } + + impl Diffable for $n { + fn diff(&self, other: &Self, field_prefix: &str) -> Vec<$crate::outbound::db_custom::write_set::FieldDiff> + where + Self: Sized + { + use $crate::outbound::db_custom::write_set::Valuable; + + let mut modifications = vec![]; + + $( + modifications.extend(self.$field_name.diff(&other.$field_name, &format!("{}{}.", field_prefix, stringify!($field_name))).into_iter()); + )* + + modifications + } + } + }; +}