From 45a68865b6abbd9bb4e7f7f2c2a9f6ab68ec2866 Mon Sep 17 00:00:00 2001 From: Markus Scully Date: Mon, 4 Aug 2025 21:03:15 +0300 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=F0=9F=8D=B1=F0=9F=92=A9?= =?UTF-8?q?=F0=9F=91=B7=20crates/vanth,=20project:=20Refactor=20entity=20s?= =?UTF-8?q?ystem=20and=20setup;=20migrate=20to=20Nix=20flakes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add `.cargo/config.toml` with target directory and rustflags configuration. - Remove devenv files and set up Nix flake configuration with `flake.nix` and `flake.lock`. - Add dependencies on `blake3`, `digest`, and hashing-related crates for content hashing functionality. - Implement `EntityId` as hashed representation and `ContentHash` component using Blake3. - Add `hashing_serializer` module for serializing and hashing components. - Remove unused `parser` module and restructure lib.rs with new `Reference` type and storage interfaces. - Add test files for `store` and `reference` functionality with TODOs for implementation. - Introduce `VanthPlugin` skeleton and entity save/load interfaces with placeholder implementations. - Add `Reference` type with retrieval state machine and async handling stubs. --- .cargo/config.toml | 3 + .envrc | 3 - .rules | 1 - Cargo.lock | 101 +++++++ Cargo.toml | 3 + crates/vanth/Cargo.toml | 2 + crates/vanth/src/entity.rs | 12 + crates/vanth/src/hashing_serializer.rs | 390 +++++++++++++++++++++++++ crates/vanth/src/lib.rs | 93 +++++- crates/vanth/src/main.rs | 3 - crates/vanth/src/parser.rs | 0 crates/vanth/src/store.rs | 17 ++ crates/vanth/tests/reference.rs | 28 ++ crates/vanth/tests/store.rs | 24 ++ devenv.lock | 178 ----------- devenv.nix | 60 ---- devenv.yaml | 14 - flake.lock | 130 +++++++++ flake.nix | 117 ++++++++ 19 files changed, 918 insertions(+), 261 deletions(-) create mode 100644 .cargo/config.toml delete mode 100644 .envrc delete mode 120000 .rules create mode 100644 crates/vanth/src/hashing_serializer.rs delete mode 100644 crates/vanth/src/parser.rs create mode 100644 crates/vanth/tests/reference.rs create mode 100644 crates/vanth/tests/store.rs delete mode 100644 devenv.lock delete mode 100644 devenv.nix delete mode 100644 devenv.yaml create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..a6b716c --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[build] +target-dir = "target/cargo" +rustflags = ["-A", "unused", "-W", "unused_must_use"] diff --git a/.envrc b/.envrc deleted file mode 100644 index 5bf8fc1..0000000 --- a/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -source_url "https://raw.githubusercontent.com/cachix/devenv/95f329d49a8a5289d31e0982652f7058a189bfca/direnvrc" "sha256-d+8cBpDfDBj41inrADaJt+bDWhOktwslgoP5YiGJ1v0=" - -use devenv \ No newline at end of file diff --git a/.rules b/.rules deleted file mode 120000 index daec0be..0000000 --- a/.rules +++ /dev/null @@ -1 +0,0 @@ -/home/asraelite/base/ai_rules/zed.md \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 38b3690..888bf24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.6" @@ -238,6 +244,29 @@ dependencies = [ "serde", ] +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -250,6 +279,15 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "cc" +version = "1.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -272,6 +310,12 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "critical-section" version = "1.2.0" @@ -293,6 +337,16 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "ctrlc" version = "3.4.7" @@ -324,6 +378,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "disqualified" version = "1.0.0" @@ -395,6 +460,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.3.3" @@ -657,6 +732,12 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "slab" version = "0.4.10" @@ -693,6 +774,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.104" @@ -756,6 +843,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -786,6 +879,8 @@ version = "0.1.0" dependencies = [ "bevy_app", "bevy_ecs", + "blake3", + "digest", "serde", "serde_json", ] @@ -801,6 +896,12 @@ dependencies = [ "syn", ] +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "wasi" version = "0.14.2+wasi-0.2.4" diff --git a/Cargo.toml b/Cargo.toml index cc3d195..b1be115 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,5 +9,8 @@ edition = "2024" [workspace.dependencies] bevy_app = "0.16.1" bevy_ecs = "0.16.1" +bitcode = "0.6.6" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" +digest = "0.10.7" +blake3 = { version = "1.8.2", features = ["traits-preview"] } diff --git a/crates/vanth/Cargo.toml b/crates/vanth/Cargo.toml index a8f0139..41c10fd 100644 --- a/crates/vanth/Cargo.toml +++ b/crates/vanth/Cargo.toml @@ -9,5 +9,7 @@ path = "src/lib.rs" [dependencies] bevy_app.workspace = true bevy_ecs.workspace = true +digest.workspace = true serde.workspace = true serde_json.workspace = true +blake3.workspace = true diff --git a/crates/vanth/src/entity.rs b/crates/vanth/src/entity.rs index 07ddd6c..a8129aa 100644 --- a/crates/vanth/src/entity.rs +++ b/crates/vanth/src/entity.rs @@ -3,6 +3,18 @@ use std::fmt::{self, Debug, Display}; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; +use crate::hash; +use crate::hashing_serializer::{self, HashingSerializer}; + +#[derive(Clone, Copy, Deserialize)] +pub struct EntityId([u8; 32]); + +impl From for EntityId { + fn from(value: String) -> Self { + Self(hash(&value).hash) + } +} + /// A generic identifier type that can be used for different entity types #[derive(Clone, Copy, Serialize, Deserialize)] pub struct Id { diff --git a/crates/vanth/src/hashing_serializer.rs b/crates/vanth/src/hashing_serializer.rs new file mode 100644 index 0000000..c51fa34 --- /dev/null +++ b/crates/vanth/src/hashing_serializer.rs @@ -0,0 +1,390 @@ +// Stolen and adapted from https://github.com/fjarri/hashing-serializer/blob/master/src/lib.rs + +use std::fmt; + +use digest::Update; +use serde::{ + ser::{ + self, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, + SerializeTupleStruct, SerializeTupleVariant, + }, + Serialize, Serializer, +}; + +use crate::ContentHash; + +pub fn hash(value: &impl Serialize) -> ContentHash { + let mut digest = blake3::Hasher::new(); + let mut serializer = HashingSerializer { digest: &mut digest }; + // TODO: Don't unwrap. + serializer.serialize_value(value).unwrap(); + ContentHash { hash: *serializer.digest.finalize().as_bytes() } +} + +/// A serializer that hashes the data instead of serializing it. +pub struct HashingSerializer<'a, T: Update> { + /// A reference to the digest that will accumulate the data. + pub digest: &'a mut T, +} + +/// Possible errors during serialization. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Error { + /// The type's [`serde::Serialize`] impl tried to serialize a sequence of undefined length. + UndefinedSequenceLength, + + /// Sequence length does not fit into `u128`. + /// + /// Really, this shouldn't ever happen. + SequenceLengthTooLarge, + + /// [`Serializer::collect_str`] got called, but heap memory allocation is not available. + /// + /// Can only be returned if `alloc` feature not enabled. + CannotCollectStr, + + /// Custom `serde` error, but memory allocation is not available. + /// Set a breakpoint where this is thrown for more information. + /// + /// Can only be returned if `alloc` feature not enabled). + CustomErrorNoAlloc, + + /// Custom `serde` error. + CustomError(String), +} + +impl ser::Error for Error { + fn custom(msg: T) -> Self { + Self::CustomError(format!("{}", msg)) + } +} + +impl ser::StdError for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +/// Converts the `usize` sequence length to a fixed length type, +/// since we want the result to be portable. +fn try_into_sequence_length(len: usize) -> Result { + u128::try_from(len) + .ok() + .ok_or(Error::SequenceLengthTooLarge) +} + +// Implement `serialize_$ty` for int types +macro_rules! impl_trivial_serialize { + ($method_name:ident , $t:ty) => { + fn $method_name(self, v: $t) -> Result { + self.digest.update(&v.to_be_bytes()); + Ok(()) + } + }; +} + +macro_rules! impl_serialize_trait { + ($method_name:ident , $t:ty) => { + fn $method_name(self, v: $t) -> Result { + self.digest.update(&v.to_be_bytes()); + Ok(()) + } + }; +} + +impl<'a, T: Update> Serializer for HashingSerializer<'a, T> { + type Ok = (); + type Error = Error; + type SerializeSeq = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeStructVariant = Self; + + fn serialize_bool(self, v: bool) -> Result { + self.digest.update(&(v as u8).to_be_bytes()); + Ok(()) + } + + impl_trivial_serialize!(serialize_i8, i8); + impl_trivial_serialize!(serialize_i16, i16); + impl_trivial_serialize!(serialize_i32, i32); + impl_trivial_serialize!(serialize_i64, i64); + + impl_trivial_serialize!(serialize_u8, u8); + impl_trivial_serialize!(serialize_u16, u16); + impl_trivial_serialize!(serialize_u32, u32); + impl_trivial_serialize!(serialize_u64, u64); + + impl_trivial_serialize!(serialize_f32, f32); + impl_trivial_serialize!(serialize_f64, f64); + + fn serialize_char(self, v: char) -> Result { + // `char` is always at most 4 bytes, regardless of the platform, + // so this conversion is safe. + self.digest.update(&u64::from(v).to_be_bytes()); + Ok(()) + } + + fn serialize_str(self, v: &str) -> Result { + self.digest.update(v.as_ref()); + Ok(()) + } + + fn serialize_bytes(self, v: &[u8]) -> Result { + self.digest.update(v); + Ok(()) + } + + fn serialize_none(self) -> Result { + self.digest.update(&[0]); + Ok(()) + } + + fn serialize_some(self, value: &V) -> Result { + self.digest.update(&[1]); + value.serialize(self) + } + + fn serialize_unit(self) -> Result { + Ok(()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Ok(()) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + ) -> Result { + self.digest.update(&variant_index.to_be_bytes()); + Ok(()) + } + + fn serialize_newtype_struct( + self, + _name: &'static str, + value: &V, + ) -> Result { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + value: &V, + ) -> Result { + self.digest.update(&variant_index.to_be_bytes()); + value.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + let len = len.ok_or(Error::UndefinedSequenceLength)?; + self.digest + .update(&try_into_sequence_length(len)?.to_be_bytes()); + Ok(self) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.digest + .update(&try_into_sequence_length(len)?.to_be_bytes()); + Ok(self) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.digest + .update(&try_into_sequence_length(len)?.to_be_bytes()); + Ok(self) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + len: usize, + ) -> Result { + self.digest.update(&variant_index.to_be_bytes()); + self.digest + .update(&try_into_sequence_length(len)?.to_be_bytes()); + Ok(self) + } + + fn serialize_map(self, len: Option) -> Result { + let len = len.ok_or(Error::UndefinedSequenceLength)?; + self.digest + .update(&try_into_sequence_length(len)?.to_be_bytes()); + Ok(self) + } + + fn serialize_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.digest + .update(&try_into_sequence_length(len)?.to_be_bytes()); + Ok(self) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + len: usize, + ) -> Result { + self.digest.update(&variant_index.to_be_bytes()); + self.digest + .update(&try_into_sequence_length(len)?.to_be_bytes()); + Ok(self) + } + + fn collect_str(self, _: &V) -> Result { + Err(Error::CannotCollectStr) + } + + fn is_human_readable(&self) -> bool { + false + } +} + +impl<'a, T: Update> SerializeSeq for HashingSerializer<'a, T> { + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, value: &V) -> Result { + value.serialize(HashingSerializer { + digest: self.digest, + })?; + Ok(()) + } + + fn end(self) -> Result { + Ok(()) + } +} + +impl<'a, T: Update> SerializeTuple for HashingSerializer<'a, T> { + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, value: &V) -> Result { + value.serialize(HashingSerializer { + digest: self.digest, + })?; + Ok(()) + } + + fn end(self) -> Result { + Ok(()) + } +} + +impl<'a, T: Update> SerializeTupleStruct for HashingSerializer<'a, T> { + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, value: &V) -> Result { + value.serialize(HashingSerializer { + digest: self.digest, + })?; + Ok(()) + } + + fn end(self) -> Result { + Ok(()) + } +} + +impl<'a, T: Update> SerializeTupleVariant for HashingSerializer<'a, T> { + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, value: &V) -> Result { + value.serialize(HashingSerializer { + digest: self.digest, + })?; + Ok(()) + } + + fn end(self) -> Result { + Ok(()) + } +} + +impl<'a, T: Update> SerializeMap for HashingSerializer<'a, T> { + type Ok = (); + type Error = Error; + + fn serialize_key(&mut self, key: &K) -> Result { + key.serialize(HashingSerializer { + digest: self.digest, + })?; + Ok(()) + } + + fn serialize_value(&mut self, value: &V) -> Result { + value.serialize(HashingSerializer { + digest: self.digest, + })?; + Ok(()) + } + + fn end(self) -> Result { + Ok(()) + } +} + +impl<'a, T: Update> SerializeStruct for HashingSerializer<'a, T> { + type Ok = (); + type Error = Error; + + fn serialize_field( + &mut self, + _key: &'static str, + value: &V, + ) -> Result { + value.serialize(HashingSerializer { + digest: self.digest, + })?; + Ok(()) + } + + fn end(self) -> Result { + Ok(()) + } +} + +impl<'a, T: Update> SerializeStructVariant for HashingSerializer<'a, T> { + type Ok = (); + type Error = Error; + + fn serialize_field( + &mut self, + _key: &'static str, + value: &V, + ) -> Result { + value.serialize(HashingSerializer { + digest: self.digest, + })?; + Ok(()) + } + + fn end(self) -> Result { + Ok(()) + } +} diff --git a/crates/vanth/src/lib.rs b/crates/vanth/src/lib.rs index 9bf253a..2b302c3 100644 --- a/crates/vanth/src/lib.rs +++ b/crates/vanth/src/lib.rs @@ -1,12 +1,23 @@ use std::marker::PhantomData; /// Library crate for the `vanth` ECS-based database node. -use bevy_app::App; +use bevy_app::{App, Plugin}; use bevy_ecs::{prelude::*, query::QueryData}; use serde::{Deserialize, Serialize}; +use crate::entity::EntityId; + pub mod store; pub mod entity; +pub mod hashing_serializer; + +pub use hashing_serializer::hash; + +pub type Result = std::result::Result; + +pub enum Error { + Other(String), +} /// A server node wrapping a Bevy App without running it. pub struct Node { @@ -31,6 +42,16 @@ impl Node { pub fn run() { } + + pub fn save(entity_id: impl Into) -> Result<()> { + // TODO + Ok(()) + } + + pub fn load(entity_id: impl Into) -> Result> { + // TODO + Ok(None) + } } #[derive(Debug, Deserialize, Component, Serialize)] @@ -50,13 +71,81 @@ pub trait VanthTuple { } +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct EntityContents { + components: Vec +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct ComponentContents { + id: String, + content_hash: ContentHash, + data: Vec, +} + +pub trait Component: Serialize { + fn id() -> String; +} + // use a macro to implement VanthTuiple here. -#[derive(Debug, Deserialize, Component, Serialize)] +#[derive(Copy, Clone, Debug, Deserialize, Component, Serialize)] pub struct ContentHash { pub hash: [u8; 32], } +#[derive(Clone, Debug, Deserialize, Component, Serialize)] +pub struct Reference { + value: ReferenceValue, + _marker: PhantomData +} + +#[derive( Clone, Debug, Deserialize, Component, Serialize)] +pub enum ReferenceValue { + Absent, + Retrieving(ReferenceRetrievalTask), + Present(Vec) +} + +impl Reference { + pub async fn take() -> T { + todo!() + } + + pub async fn get() -> Handle { + todo!() + } +} + +#[derive(Component, Clone, Debug, Deserialize, Serialize)] +struct ReferenceRetrievalTask { + +} + +impl Future for ReferenceRetrievalTask { + type Output = Vec; + + fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll { + todo!() + } +} + +pub struct Handle { + _marker: PhantomData +} + // TODO: // A trait is derivable for ECS components // The components must have a content hash, not the entity. For efficiency and ergonomics. This means that a hash of each relevant component must be stored in the Vanth component of the entity, in a `HashMap` or something. The ID of the component used by Vanth should be a method on the derived trait. + +pub struct VanthPlugin; + +impl Plugin for VanthPlugin { + fn build(&self, app: &mut App) { + + } +} + +// fn run_reference_tasks(tasks: Query<(&ReferenceGetTask<>)>) { + +// } diff --git a/crates/vanth/src/main.rs b/crates/vanth/src/main.rs index 7cb230f..e549b26 100644 --- a/crates/vanth/src/main.rs +++ b/crates/vanth/src/main.rs @@ -1,6 +1,3 @@ -#![allow(unused)] - -mod parser; mod util; mod vanth; diff --git a/crates/vanth/src/parser.rs b/crates/vanth/src/parser.rs deleted file mode 100644 index e69de29..0000000 diff --git a/crates/vanth/src/store.rs b/crates/vanth/src/store.rs index b051826..4770af3 100644 --- a/crates/vanth/src/store.rs +++ b/crates/vanth/src/store.rs @@ -11,3 +11,20 @@ pub struct Store { impl Store { } + +#[derive(Debug, Deserialize, Component, Serialize)] +pub struct Cache { + size_limit_bytes: u64, + backend: Backend, +} + +#[derive(Debug, Deserialize, Serialize)] +pub enum Backend { + Memory, + Sqlite(Sqlite) +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Sqlite { + path: PathBuf, +} diff --git a/crates/vanth/tests/reference.rs b/crates/vanth/tests/reference.rs new file mode 100644 index 0000000..fb91860 --- /dev/null +++ b/crates/vanth/tests/reference.rs @@ -0,0 +1,28 @@ +use serde::{Deserialize, Serialize}; +use vanth::{Component, Node, Reference}; + +// #[test] +// fn test_store() { +// #[derive(Clone, Deserialize, Serialize)] +// struct Foo { +// bar: Reference, +// } + +// #[derive(Clone, Deserialize, Serialize)] +// struct Bar { +// foo: Reference, +// } + +// impl Component for Foo { +// fn id() -> String { +// "foo".into() +// } +// } + +// let node = Node::in_memory(); + +// let entity_id = "entity_1"; +// let entity_components = (Foo { a: 5, b: 6.0 },); + +// node.save("entity_1", entity_components); +// } diff --git a/crates/vanth/tests/store.rs b/crates/vanth/tests/store.rs new file mode 100644 index 0000000..e1e2646 --- /dev/null +++ b/crates/vanth/tests/store.rs @@ -0,0 +1,24 @@ +use serde::{Deserialize, Serialize}; +use vanth::{Component, Node}; + +// #[test] +// fn test_store() { +// #[derive(Deserialize, Serialize)] +// struct Foo { +// a: u32, +// b: f32, +// } + +// impl Component for Foo { +// fn id() -> String { +// "foo".into() +// } +// } + +// let node = Node::in_memory(); + +// let entity_id = "entity_1"; +// let entity_components = (Foo { a: 5, b: 6.0 },); + +// node.save("entity_1", entity_components); +// } diff --git a/devenv.lock b/devenv.lock deleted file mode 100644 index 3d25646..0000000 --- a/devenv.lock +++ /dev/null @@ -1,178 +0,0 @@ -{ - "nodes": { - "devenv": { - "locked": { - "dir": "src/modules", - "lastModified": 1731619804, - "owner": "cachix", - "repo": "devenv", - "rev": "87edaaf1dddf17fe16eabab3c8edaf7cca2c3bc2", - "treeHash": "c0c2fd8edf08b32c9da79d4bb917690dc5b126d0", - "type": "github" - }, - "original": { - "dir": "src/modules", - "owner": "cachix", - "repo": "devenv", - "type": "github" - } - }, - "fenix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ], - "rust-analyzer-src": "rust-analyzer-src" - }, - "locked": { - "lastModified": 1731565929, - "owner": "nix-community", - "repo": "fenix", - "rev": "4c6c7d5088f12f57afd4ba6449f9eb168ca05620", - "treeHash": "06a361535bdfec44eb64eb02dc5628ea71b2f488", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "fenix", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "treeHash": "2addb7b71a20a25ea74feeaf5c2f6a6b30898ecb", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "gitignore": { - "inputs": { - "nixpkgs": [ - "pre-commit-hooks", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1709087332, - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", - "treeHash": "ca14199cabdfe1a06a7b1654c76ed49100a689f9", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1716977621, - "owner": "cachix", - "repo": "devenv-nixpkgs", - "rev": "4267e705586473d3e5c8d50299e71503f16a6fb6", - "treeHash": "6d9f1f7ca0faf1bc2eeb397c78a49623260d3412", - "type": "github" - }, - "original": { - "owner": "cachix", - "ref": "rolling", - "repo": "devenv-nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1731386116, - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "689fed12a013f56d4c4d3f612489634267d86529", - "treeHash": "8786ed18f037bad8b80b7a75c0e7b21a6769ee87", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-unstable": { - "locked": { - "lastModified": 1731531548, - "owner": "nixos", - "repo": "nixpkgs", - "rev": "24f0d4acd634792badd6470134c387a3b039dace", - "treeHash": "a35f71a0fa18e0a51dfeead7b9c971ed73043752", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1731363552, - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0", - "treeHash": "d246c8c2f312332367d56063d2b049419880acc7", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, - "root": { - "inputs": { - "devenv": "devenv", - "fenix": "fenix", - "nixpkgs": "nixpkgs", - "nixpkgs-unstable": "nixpkgs-unstable", - "pre-commit-hooks": "pre-commit-hooks" - } - }, - "rust-analyzer-src": { - "flake": false, - "locked": { - "lastModified": 1731342671, - "owner": "rust-lang", - "repo": "rust-analyzer", - "rev": "fc98e0657abf3ce07eed513e38274c89bbb2f8ad", - "treeHash": "7c4a6b17fbe9e655cac7d03a3c034456b8f60a1f", - "type": "github" - }, - "original": { - "owner": "rust-lang", - "ref": "nightly", - "repo": "rust-analyzer", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/devenv.nix b/devenv.nix deleted file mode 100644 index 5aa697f..0000000 --- a/devenv.nix +++ /dev/null @@ -1,60 +0,0 @@ -{ - pkgs, - lib, - config, - inputs, - ... -}: - -let - pkgs-unstable = import inputs.nixpkgs-unstable { - system = pkgs.stdenv.system; - config.allowUnfree = true; - }; -in -{ - # https://devenv.sh/basics/ - env.GREET = "devenv"; - - # https://devenv.sh/packages/ - packages = [ - pkgs-unstable.git - pkgs-unstable.rustup - pkgs-unstable.code-cursor - pkgs-unstable.curl - pkgs-unstable.jq - ]; - - # https://devenv.sh/languages/ - languages.rust = { - channel = "nightly"; - components = [ - "cargo" - "rust-src" - "rustc" - "clippy" - ]; - enable = true; - }; - - enterShell = '' - rustup component add clippy - ''; - - enterTest = '' - echo "Running tests" - git --version | grep --color=auto "${pkgs.git.version}" - cargo clippy -- -D warnings - ''; - - pre-commit.hooks = { - shellcheck.enable = true; - clippy = { - enable = true; - name = "clippy"; - entry = "cargo clippy -- -D warnings"; - files = "\\.rs$"; - language = "system"; - }; - }; -} diff --git a/devenv.yaml b/devenv.yaml deleted file mode 100644 index 90a9f99..0000000 --- a/devenv.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json -inputs: - fenix: - url: github:nix-community/fenix - inputs: - nixpkgs: - follows: nixpkgs - nixpkgs: - url: github:cachix/devenv-nixpkgs/rolling - nixpkgs-unstable: - url: github:nixos/nixpkgs/nixpkgs-unstable - -allowUnfree: true - diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..7712995 --- /dev/null +++ b/flake.lock @@ -0,0 +1,130 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1754112045, + "narHash": "sha256-ZgsUm1brDXTPSLK5kY5rkQkqqr2oM1Pd20oirH3Sgkk=", + "owner": "ipetkov", + "repo": "crane", + "rev": "b91f27c93d9d414a21092d85ed5ac9def8624b91", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "fenix": { + "inputs": { + "nixpkgs": "nixpkgs", + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1754116698, + "narHash": "sha256-2cMDogXcqv975o191g0/6ZM0UolJ2X0ChuuLaNKbNAM=", + "owner": "nix-community", + "repo": "fenix", + "rev": "acdb7d8af407ea8aee21b028dc58b4bc51a7849a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1754091436, + "narHash": "sha256-XKqDMN1/Qj1DKivQvscI4vmHfDfvYR2pfuFOJiCeewM=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "67df8c627c2c39c41dbec76a1f201929929ab0bd", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1753939845, + "narHash": "sha256-K2ViRJfdVGE8tpJejs8Qpvvejks1+A4GQej/lBk5y7I=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "94def634a20494ee057c76998843c015909d6311", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1753579242, + "narHash": "sha256-zvaMGVn14/Zz8hnp4VWT9xVnhc8vuL3TStRqwk22biA=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "0f36c44e01a6129be94e3ade315a5883f0228a6e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1754060105, + "narHash": "sha256-di5L6e5Iiv+oegS07j9h23FdqEpXn0ZQqMlDOEMw1EY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e7eabdc701d7dbb810fd91a97ec358caa4c1fc50", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "fenix": "fenix", + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs_2" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1753974682, + "narHash": "sha256-Ya4Ecj8JaKkapgYCCybzZBcypXpblhuG0hVDzdy2zyo=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "68e7ec90bf29c9b17d0dcdb3358de5dee7f4afb5", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..a8fe991 --- /dev/null +++ b/flake.nix @@ -0,0 +1,117 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + crane.url = "github:ipetkov/crane"; + flake-parts.url = "github:hercules-ci/flake-parts"; + fenix.url = "github:nix-community/fenix"; + }; + + outputs = + inputs@{ flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ + "aarch64-linux" + "aarch64-darwin" + "x86_64-darwin" + "x86_64-linux" + ]; + + perSystem = + { pkgs, system, ... }: + let + rustToolchain = inputs.fenix.packages.${system}.combine ([ + (inputs.fenix.packages.${system}.complete.withComponents [ + "cargo" + "clippy" + "rust-src" + "rustc" + "rustfmt" + ]) + inputs.fenix.packages.${system}.complete.rust-analyzer + inputs.fenix.packages.${system}.targets.wasm32-unknown-unknown.latest.rust-std + ]); + craneLib = (inputs.crane.mkLib pkgs).overrideToolchain rustToolchain; + + packages = + with pkgs; + [ + dbus + libssh2 + makeWrapper + openssl + openssl.dev + pkg-config + ] + ++ lib.optionals stdenv.isLinux [ + systemd + patchelf + ] + ++ lib.optionals stdenv.isDarwin [ + libiconv + darwin.apple_sdk.frameworks.Security + darwin.apple_sdk.frameworks.SystemConfiguration + darwin.apple_sdk.frameworks.AudioUnit + darwin.apple_sdk.frameworks.CoreAudio + ]; + + commonArgs = { + src = ./.; + strictDeps = true; + nativeBuildInputs = packages; + buildInputs = packages; + + CARGO_BUILD_INCREMENTAL = "false"; + RUST_BACKTRACE = "1"; + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath packages; + }; + + craneArgs = { + }; + + cargoArtifacts = craneLib.buildDepsOnly ( + commonArgs + // craneArgs + // { + pname = "vanth-deps"; + version = "0.1.0"; + } + ); + + vanth = craneLib.buildPackage ( + commonArgs + // craneArgs + // { + inherit cargoArtifacts; + pname = "vanth"; + version = "0.1.0"; + cargoExtraArgs = "--package vanth_cli"; + + postInstall = '' + if [ ! -f "$out/bin/vanth" ]; then + echo "Error: vanth binary not found in $out/bin/" + ls -la $out/bin/ + exit 1 + fi + '' + + pkgs.lib.optionalString pkgs.stdenv.isLinux '' + patchelf $out/bin/vanth --set-rpath ${pkgs.lib.makeLibraryPath packages} + wrapProgram $out/bin/vanth --set LD_LIBRARY_PATH "${pkgs.lib.makeLibraryPath packages}" + ''; + } + ); + in + { + packages = rec { + inherit vanth; + default = vanth; + }; + + devShells.default = craneLib.devShell { + inputsFrom = [ vanth ]; + packages = packages; + RUST_SRC_PATH = "${rustToolchain}/lib/rustlib/src/rust/library"; + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath packages; + }; + }; + }; +}