mirror of https://github.com/pcleavelin/a_ci.git
write the dumbest macro I could think of
parent
a47bfec6bc
commit
5dd8d1f5cd
|
|
@ -10,6 +10,7 @@ dependencies = [
|
|||
"axum",
|
||||
"bincode",
|
||||
"dotenv",
|
||||
"field_types",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -30,9 +31,9 @@ version = "0.1.89"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -211,9 +212,9 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -253,6 +254,17 @@ 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"
|
||||
|
|
@ -399,6 +411,15 @@ 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"
|
||||
|
|
@ -707,9 +728,9 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -751,9 +772,9 @@ version = "1.1.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -783,6 +804,15 @@ 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"
|
||||
|
|
@ -792,13 +822,22 @@ 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",
|
||||
"proc-macro2 1.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -938,9 +977,9 @@ version = "1.0.228"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1043,14 +1082,25 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||
|
||||
[[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",
|
||||
"quote",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
|
|
@ -1066,9 +1116,9 @@ version = "0.13.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1120,9 +1170,9 @@ version = "1.0.69"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1157,9 +1207,9 @@ version = "2.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1269,6 +1319,18 @@ 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 = "unty"
|
||||
version = "0.0.4"
|
||||
|
|
@ -1367,7 +1429,7 @@ version = "0.2.105"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"quote 1.0.41",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
|
|
@ -1378,9 +1440,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
|
@ -1670,9 +1732,9 @@ version = "0.8.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -1691,9 +1753,9 @@ version = "0.1.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -1725,7 +1787,7 @@ version = "0.11.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.103",
|
||||
"quote 1.0.41",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ anyhow = "1.0.100"
|
|||
axum = { version = "0.6.9", features = ["headers"] }
|
||||
bincode = "2.0.1"
|
||||
dotenv = "0.15.0"
|
||||
field_types = "1.1.0"
|
||||
reqwest = "0.11.14"
|
||||
serde = "1.0.152"
|
||||
serde_json = "1.0.93"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ use std::{
|
|||
|
||||
use crate::outbound::db_custom::write_set::{Diffable, Storable, Write, WriteOperation, WriteSet};
|
||||
|
||||
#[derive(Default, Copy, Clone, PartialOrd, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(
|
||||
Default, Copy, Clone, PartialOrd, PartialEq, Eq, Hash, Debug, bincode::Encode, bincode::Decode,
|
||||
)]
|
||||
struct TransactionId(u64);
|
||||
|
||||
impl From<u64> for TransactionId {
|
||||
|
|
@ -179,6 +181,9 @@ impl Database {
|
|||
|
||||
self.log.push(Transaction::commit(timestamp, candidate));
|
||||
self.build_snapshot(timestamp);
|
||||
|
||||
let b = bincode::encode_to_vec(&self.log, bincode::config::standard())
|
||||
.expect("encode MUST succeed");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +267,7 @@ impl DatabaseAccessor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, bincode::Encode, bincode::Decode)]
|
||||
struct Transaction {
|
||||
id: TransactionId,
|
||||
write_set: WriteSet,
|
||||
|
|
@ -496,21 +501,26 @@ impl Value {
|
|||
mod tests {
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::outbound::db_custom::write_set::FieldDiff;
|
||||
use crate::{db_type, outbound::db_custom::write_set::FieldDiff};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone, bincode::Encode, bincode::Decode)]
|
||||
struct MyTestData {
|
||||
name: Name,
|
||||
age: i64,
|
||||
contacts: HashSet<Id<Self>>,
|
||||
}
|
||||
db_type! {
|
||||
struct MyTestData {
|
||||
name: Name,
|
||||
age: i64,
|
||||
contacts: (HashSet<Id<Self>>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, bincode::Encode, bincode::Decode)]
|
||||
struct Name {
|
||||
first: String,
|
||||
last: String,
|
||||
struct Name {
|
||||
first: String,
|
||||
last: String,
|
||||
nest: SuperNested,
|
||||
}
|
||||
|
||||
struct SuperNested {
|
||||
i_am_a_really_nested_field: i64,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(bincode::Encode)]
|
||||
|
|
@ -528,120 +538,6 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
impl Storable for MyTestData {
|
||||
fn as_full_write_op(&self) -> WriteOperation
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let data =
|
||||
bincode::encode_to_vec(A::with("MyTestData", self), bincode::config::standard())
|
||||
.expect("encode MUST succeed");
|
||||
|
||||
WriteOperation::Full(data)
|
||||
}
|
||||
|
||||
fn as_partial_write_op(&self, other: &Self) -> WriteOperation
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
WriteOperation::Partial(self.diff(other).into_iter().map(Into::into).collect())
|
||||
}
|
||||
|
||||
fn apply_partial_write(&mut self, op: &write_set::PartialWrite) {
|
||||
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,
|
||||
{
|
||||
match field_ident {
|
||||
"name.first" => {
|
||||
let Value::String(name) = value else {
|
||||
panic!("expected 'name.first' to be a 'String'");
|
||||
};
|
||||
|
||||
self.name.first = name;
|
||||
}
|
||||
"name.last" => {
|
||||
let Value::String(name) = value else {
|
||||
panic!("expected 'name.last' to be a 'String'");
|
||||
};
|
||||
|
||||
self.name.last = name;
|
||||
}
|
||||
"age" => {
|
||||
let Value::Int(age) = value else {
|
||||
panic!("expected 'age' to be a 'Int'");
|
||||
};
|
||||
|
||||
self.age = age;
|
||||
}
|
||||
"contacts" => {
|
||||
let Value::Array(contacts) = value else {
|
||||
panic!("expected 'contacts' to be a 'Vec<Id>'");
|
||||
};
|
||||
|
||||
self.contacts = contacts.into_iter().map(|id| Id::<_>::new(id.0)).collect();
|
||||
}
|
||||
_ => panic!("invalid field '{field_ident}'"),
|
||||
};
|
||||
}
|
||||
|
||||
fn field(&self, field_ident: &str) -> Option<Value>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match field_ident {
|
||||
"name.first" => Some(Value::String(self.name.first.clone())),
|
||||
"name.last" => Some(Value::String(self.name.last.clone())),
|
||||
"age" => Some(Value::Int(self.age)),
|
||||
"contacts" => Some(Value::Array(
|
||||
self.contacts.iter().map(|id| id.into()).collect(),
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Diffable for MyTestData {
|
||||
fn diff(&self, other: &Self) -> Vec<FieldDiff>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut modifications = vec![];
|
||||
|
||||
if self.name.first != other.name.first {
|
||||
modifications.push(FieldDiff::of(
|
||||
"name.first",
|
||||
Value::String(other.name.first.clone()),
|
||||
));
|
||||
}
|
||||
|
||||
if self.name.last != other.name.last {
|
||||
modifications.push(FieldDiff::of(
|
||||
"name.last",
|
||||
Value::String(other.name.last.clone()),
|
||||
));
|
||||
}
|
||||
|
||||
if self.age != other.age {
|
||||
modifications.push(FieldDiff::of("age", Value::Int(other.age)));
|
||||
}
|
||||
|
||||
let contacts_diff = self.contacts.difference(&other.contacts);
|
||||
if contacts_diff.count() > 0 {
|
||||
modifications.push(FieldDiff::of(
|
||||
"contacts",
|
||||
Value::Array(other.contacts.iter().map(|id| id.into()).collect()),
|
||||
));
|
||||
}
|
||||
|
||||
modifications
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut db = Database::default();
|
||||
|
|
@ -659,9 +555,12 @@ mod tests {
|
|||
name: Name {
|
||||
first: "John".to_string(),
|
||||
last: "Doe".to_string(),
|
||||
nest: SuperNested {
|
||||
i_am_a_really_nested_field: 67,
|
||||
},
|
||||
},
|
||||
age: 42,
|
||||
contacts: HashSet::new(),
|
||||
contacts: vec![Id::new(1)].into_iter().collect(),
|
||||
};
|
||||
|
||||
println!("initial state: {:#?}", accessor.db.lock().unwrap());
|
||||
|
|
@ -674,6 +573,9 @@ mod tests {
|
|||
name: Name {
|
||||
first: "Oldy".to_string(),
|
||||
last: "McOlderton".to_string(),
|
||||
nest: SuperNested {
|
||||
i_am_a_really_nested_field: 32,
|
||||
},
|
||||
},
|
||||
age: 69,
|
||||
contacts: vec![Id::new(1)].into_iter().collect(),
|
||||
|
|
@ -691,6 +593,8 @@ mod tests {
|
|||
};
|
||||
|
||||
t.modify(Id::<MyTestData>::new(1), |mut data| {
|
||||
data.age = 9;
|
||||
data.name.nest.i_am_a_really_nested_field = 9;
|
||||
data.name.last = format!("Gearbox {}", last_name_of_oldy);
|
||||
data
|
||||
});
|
||||
|
|
@ -700,6 +604,7 @@ mod tests {
|
|||
let id = Id::<MyTestData>::new(1);
|
||||
accessor.transact(|t| {
|
||||
t.modify(id.clone(), |mut data| {
|
||||
data.age = 9;
|
||||
data.name.last = "Not McOlderton Gearbox".to_string();
|
||||
|
||||
data
|
||||
|
|
|
|||
|
|
@ -75,3 +75,212 @@ pub struct PartialWrite {
|
|||
pub(super) field_ident: String,
|
||||
pub(super) data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! primitive_assign {
|
||||
($self:ident, $field_name:ident, $value:ident, $ty:ty, $variant:ident) => {{
|
||||
let Value::$variant(value) = $value else {
|
||||
panic!(
|
||||
"expected '{}' to be a '{}'",
|
||||
stringify!($field_name),
|
||||
stringify!($ty)
|
||||
);
|
||||
};
|
||||
|
||||
$self.$field_name = value;
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! primitive_return {
|
||||
($self:ident, $field_name:ident, $variant:ident) => {
|
||||
Some(Value::$variant($self.$field_name.clone()))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! db_type {
|
||||
($self:ident, $field_name:ident, i64, $value:ident, $field_ident:ident) => {
|
||||
$crate::primitive_assign!($self, $field_name, $value, i64, Int)
|
||||
};
|
||||
($self:ident, $field_name:ident, String, $value:ident, $field_ident:ident) => {
|
||||
$crate::primitive_assign!($self, $field_name, $value, String, String)
|
||||
};
|
||||
|
||||
($self:ident, $field_name:ident, (HashSet<Id<$ty:ty>>), $value:ident, $field_ident:ident) => {
|
||||
{
|
||||
let Value::Array(value) = $value else {
|
||||
panic!(
|
||||
"expected '{}' to be a 'Vec<Id<{}>>'",
|
||||
stringify!($field_name),
|
||||
stringify!($ty)
|
||||
);
|
||||
};
|
||||
|
||||
$self.$field_name = value.into_iter().map(|id| Id::<_>::new(id.0)).collect();
|
||||
}
|
||||
};
|
||||
|
||||
($self:ident, $field_name:ident, $field_type:ty, $value:ident, $field_ident:ident) => {
|
||||
{
|
||||
let field_name_len = stringify!($field_name).len();
|
||||
if field_name_len == $field_ident.len() {
|
||||
panic!("attempt to assign non-primitive");
|
||||
}
|
||||
|
||||
$self.$field_name.set_field(&$field_ident[(field_name_len+1)..], $value);
|
||||
}
|
||||
};
|
||||
|
||||
($self:ident, $field_name:ident, i64, $field_ident:ident) => {{
|
||||
Some(Value::Int($self.$field_name.clone()))
|
||||
}};
|
||||
($self:ident, $field_name:ident, String, $field_ident:ident) => {{
|
||||
Some(Value::String($self.$field_name.clone()))
|
||||
}};
|
||||
($self:ident, $field_name:ident, (HashSet<Id<$ty:ty>>), $field_ident:ident) => {
|
||||
Some(Value::Array($self.$field_name.iter().map(|id| id.into()).collect()))
|
||||
};
|
||||
($self:ident, $field_name:ident, $field_type:ty, $field_ident:ident) => {{
|
||||
let field_name_len = stringify!($field_name).len();
|
||||
if field_name_len == $field_ident.len() {
|
||||
panic!("attempt to assign non-primitive");
|
||||
}
|
||||
|
||||
$self.$field_name.field(&$field_ident[(field_name_len+1)..])
|
||||
}};
|
||||
|
||||
(@diff $self:ident, $other:ident, $modifications:ident, $field_name:ident, i64) => {
|
||||
if $self.$field_name != $other.$field_name {
|
||||
$modifications.push(FieldDiff::of(
|
||||
stringify!($field_name),
|
||||
Value::Int($other.$field_name.clone()),
|
||||
));
|
||||
}
|
||||
};
|
||||
(@diff $self:ident, $other:ident, $modifications:ident, $field_name:ident, String) => {
|
||||
if $self.$field_name != $other.$field_name {
|
||||
$modifications.push(FieldDiff::of(
|
||||
stringify!($field_name),
|
||||
Value::String($other.$field_name.clone()),
|
||||
));
|
||||
}
|
||||
};
|
||||
(@diff $self:ident, $other:ident, $modifications:ident, $field_name:ident, (HashSet<Id<$ty:ty>>)) => {
|
||||
let diff = $self.$field_name.difference(&$other.$field_name);
|
||||
if diff.count() > 0 {
|
||||
$modifications.push(FieldDiff::of(
|
||||
stringify!($field_name),
|
||||
Value::Array($other.$field_name.iter().map(|id| id.into()).collect())
|
||||
));
|
||||
}
|
||||
};
|
||||
(@diff $self:ident, $other:ident, $modifications:ident, $field_name:ident, $field_type:ty) => {
|
||||
$modifications.extend(
|
||||
$self.$field_name
|
||||
.diff(&$other.$field_name)
|
||||
.into_iter()
|
||||
.map(|diff| {
|
||||
// NOTE(pcleavelin): we have to recreate the `field_ident` path via recursive
|
||||
// string building lol
|
||||
FieldDiff::of(
|
||||
format!("{}.{}", stringify!($field_name), &diff.field_ident),
|
||||
diff.value
|
||||
)
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
{
|
||||
$(
|
||||
struct $db_type_name:ident {
|
||||
$(
|
||||
$field_name:ident: $field_type:tt,
|
||||
)*
|
||||
}
|
||||
)*
|
||||
} => {
|
||||
$(
|
||||
#[derive(Debug, Clone, ::bincode::Encode, ::bincode::Decode)]
|
||||
pub struct $db_type_name {
|
||||
$(
|
||||
$field_name: $field_type,
|
||||
)*
|
||||
}
|
||||
|
||||
impl Storable for $db_type_name {
|
||||
fn as_full_write_op(&self) -> WriteOperation
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let data =
|
||||
bincode::encode_to_vec(A::with(stringify!($db_type_name), self), bincode::config::standard())
|
||||
.expect("encode MUST succeed");
|
||||
|
||||
WriteOperation::Full(data)
|
||||
}
|
||||
fn as_partial_write_op(&self, other: &Self) -> WriteOperation
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
WriteOperation::Partial(self.diff(other).into_iter().map(Into::into).collect())
|
||||
}
|
||||
|
||||
fn apply_partial_write(&mut self, op: &write_set::PartialWrite) {
|
||||
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,
|
||||
{
|
||||
let mut idents = field_ident.split(".");
|
||||
let next = idents.next().unwrap();
|
||||
|
||||
match next {
|
||||
$(
|
||||
stringify!($field_name) => {
|
||||
db_type!(self, $field_name, $field_type, value, field_ident)
|
||||
}
|
||||
),*
|
||||
|
||||
_ => panic!("set_field: invalid field '{next}'"),
|
||||
}
|
||||
}
|
||||
|
||||
fn field(&self, field_ident: &str) -> Option<Value>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut idents = field_ident.split(".");
|
||||
let next = idents.next().unwrap();
|
||||
|
||||
match next {
|
||||
$(
|
||||
stringify!($field_name) => {
|
||||
db_type!(self, $field_name, $field_type, field_ident)
|
||||
}
|
||||
),*
|
||||
|
||||
_ => panic!("field: invalid field '{next}'"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Diffable for $db_type_name {
|
||||
fn diff(&self, other: &Self) -> Vec<FieldDiff>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut modifications = vec![];
|
||||
|
||||
$(
|
||||
db_type!(@diff self, other, modifications, $field_name, $field_type);
|
||||
)*
|
||||
|
||||
modifications
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue