♻️ bevy_vanth, vanth, vanth_derive, flake: Add Bevy integration crate and refactor entity/networking

- Created new crate `bevy_vanth` with basic plugin structure for Bevy integration.
- Refactored `Id` generation in `vanth` to use `OsRng` and removed redundant `to_u128_pair`/`from_u128_pair` methods.
- Moved networking functionality into new `net` module with `Node`, `Packet`, and `Message` types.
- Updated `vanth_derive` to use `proc-macro-crate` for reliable crate path resolution.
- Added `rand` dependency to replace custom ID generation logic.
- Updated `Cargo.toml`/`Cargo.lock` with new dependencies: `bevy_app`, `nix`, `cfg_aliases`, `proc-macro-crate`.
- Modified `README.md` with improved project description.
- Added commented clippy check in `flake.nix`.
This commit is contained in:
Markus Scully 2025-08-17 11:56:34 +03:00
parent 5262a266c0
commit 3b193c5aa3
Signed by: mascully
GPG key ID: 93CA5814B698101C
13 changed files with 298 additions and 127 deletions

View file

@ -0,0 +1,8 @@
[package]
name = "bevy_vanth"
version.workspace = true
edition.workspace = true
[dependencies]
bevy_ecs.workspace = true
bevy_app.workspace = true

View file

@ -0,0 +1,20 @@
use bevy_app::Plugin;
use bevy_ecs::component::Component;
#[derive(Component)]
pub struct VanthRoot {}
pub struct VanthPlugin {}
impl Plugin for VanthPlugin {
fn build(&self, app: &mut bevy_app::App) {
// TODO: Allow specifying custom schedules.
app.add_systems(bevy_app::FixedPreUpdate, run_vanth).finish();
}
}
impl VanthPlugin {}
fn run_vanth() {
}

View file

@ -16,6 +16,7 @@ blake3.workspace = true
vanth_derive = { path = "../vanth_derive" }
rusqlite.workspace = true
tracing.workspace = true
rand = { workspace = true }
[dev-dependencies]
tempfile = { workspace = true }

View file

@ -1,12 +1,12 @@
use serde::{Deserialize, Serialize};
use vanth::{hash, Vanth};
// use serde::{Deserialize, Serialize};
// use vanth::{hash, Vanth};
#[derive(Clone, Debug, Deserialize, Serialize, Vanth)]
struct Foo {
value: i32,
}
// #[derive(Clone, Debug, Deserialize, Serialize, Vanth)]
// struct Foo {
// value: i32,
// }
fn main() {
let x = "hello";
println!("Hash: {:?}", hash(&x).hex());
// let x = "hello";
// println!("Hash: {:?}", hash(&x).hex());
}

View file

@ -1,11 +1,12 @@
use crate::hash;
use crate::hashing_serializer::{self, HashingSerializer};
use rand::rngs::OsRng;
use rand::TryRngCore;
use serde::{Deserialize, Serialize};
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]);
@ -16,7 +17,7 @@ impl From<String> for EntityId {
}
/// A generic identifier type that can be used for different entity types
#[derive(Clone, Copy, Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Id<T: ?Sized> {
/// The raw identifier value
pub value: [u8; 32],
@ -37,14 +38,7 @@ impl<T: ?Sized> Id<T> {
/// Generate a random ID
pub fn random() -> Self {
let mut value = [0u8; 32];
// Simple random generation for demonstration
for i in 0..32 {
value[i] = (std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos() as u8)
.wrapping_add(i as u8);
}
OsRng.try_fill_bytes(&mut value).unwrap();
Self::new(value)
}
@ -67,42 +61,6 @@ impl<T: ?Sized> Id<T> {
}
Self::new(bytes)
}
/// Convert the ID to a pair of u128 values for handling larger values
/// Returns (high_bits, low_bits)
pub fn to_u128_pair(&self) -> (u128, u128) {
let mut high = 0u128;
let mut low = 0u128;
// First 16 bytes go to low
for i in 0..16 {
low |= (self.value[i] as u128) << (i * 8);
}
// Next 16 bytes go to high
for i in 0..16 {
high |= (self.value[i + 16] as u128) << (i * 8);
}
(high, low)
}
/// Create an ID from a pair of u128 values
pub fn from_u128_pair(high: u128, low: u128) -> Self {
let mut bytes = [0u8; 32];
// Low bits fill first 16 bytes
for i in 0..16 {
bytes[i] = ((low >> (i * 8)) & 0xFF) as u8;
}
// High bits fill next 16 bytes
for i in 0..16 {
bytes[i + 16] = ((high >> (i * 8)) & 0xFF) as u8;
}
Self::new(bytes)
}
}
impl<T: ?Sized> PartialEq for Id<T> {
@ -119,20 +77,6 @@ impl<T: ?Sized> Hash for Id<T> {
}
}
impl<T: ?Sized> Debug for Id<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (high, low) = self.to_u128_pair();
write!(f, "Id<{}>({:016x}{:016x})", std::any::type_name::<T>(), high, low)
}
}
impl<T: ?Sized> Display for Id<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (high, low) = self.to_u128_pair();
write!(f, "{:016x}{:016x}", high, low)
}
}
pub struct ContentHash {
value: [u8; 32],
}

View file

@ -7,10 +7,12 @@ use crate::entity::EntityId;
pub mod entity;
pub mod hashing_serializer;
pub mod net;
pub mod nix;
pub mod store;
pub use hashing_serializer::hash;
pub use net::Node;
pub use vanth_derive::Vanth;
pub type Result<T> = std::result::Result<T, Error>;
@ -19,41 +21,6 @@ pub enum Error {
Other(String),
}
/// A view of all of the [`Node`]s in a cluster.
pub struct Network {
// TODO
}
/// A Vanth server.
pub struct Node {
// TODO
}
impl Node {
pub fn new() -> Self {
Self {}
}
pub fn entity_count(&self) -> usize {
todo!()
}
pub fn run() {
todo!()
}
pub fn save(entity_id: impl Into<EntityId>) -> Result<()> {
// TODO
Ok(())
}
// pub fn load(entity_id: impl Into<EntityId>) -> Result<Option<EntityContents>> {
// // TODO
// Ok(None)
// }
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct HashedValue {
content_hash: ContentHash,
@ -75,9 +42,15 @@ pub struct Value {
data: Vec<u8>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct EventTy(Ty);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct TaskTy(Ty);
/// A wrapper for the fully-qualified name of a Rust type. This should be univerisally unique for a given type within a
/// given project.
#[derive(Clone, Debug, Deserialize, Serialize, Eq, Hash)]
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct Ty {
pub path: Vec<String>,
}
@ -88,12 +61,6 @@ impl ToString for Ty {
}
}
impl PartialEq for Ty {
fn eq(&self, other: &Self) -> bool {
self.path == other.path
}
}
impl<T: AsRef<str>> PartialEq<T> for Ty {
fn eq(&self, other: &T) -> bool {
self.to_string() == *other.as_ref()
@ -182,5 +149,49 @@ pub struct Handle<T> {
_marker: PhantomData<T>,
}
pub trait Task {
type Output: Vanth + Serialize + DeserializeOwned;
// TODO: Make async?
fn execute(self) -> Self::Output;
}
/// A representation of the approximate computational cost of completing a task.
pub struct Cost {
value: f64,
}
/// A world which Vanth entities live in. Lifetimes `'v` of [`Vanth<'v>`] types are tied to the lifetime of the `Root`.
pub struct Root {}
pub struct Root {
current_epoch: u64,
}
pub trait Module {
fn register(world_context: &mut ModuleRegistration);
}
pub struct ModuleRegistration {
events: Vec<EventTy>,
}
impl ModuleRegistration {}
pub trait ModuleTools: Module {
type Tool: Tool;
fn tools(&self) -> impl Iterator<Item = Self::Tool>;
}
pub trait Tool: Send + Sync {
type Input;
type Output;
type Error: std::error::Error;
fn name<'a>() -> &'a str;
fn description<'a>() -> &'a str;
fn call(
&self,
input: Self::Input,
) -> impl Future<Output = std::result::Result<Self::Output, Self::Error>> + Send;
}

63
crates/vanth/src/net.rs Normal file
View file

@ -0,0 +1,63 @@
use serde::{Deserialize, Serialize};
use crate::{Error, Result};
use crate::{
Vanth,
entity::{EntityId, Id},
};
pub struct Packet {
pub source_node: Id<Node>,
pub signature: Vec<u8>,
pub message: Message,
}
#[derive(Clone, Debug, Deserialize, Serialize, Vanth)]
pub struct Message {
pub events: Vec<Event>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Vanth)]
pub enum Event {}
/// A view of all of the [`Node`]s in a cluster.
pub struct Network {
// TODO
}
/// A Vanth server.
pub struct Node {
id: Id<Node>,
}
impl Node {
pub fn new() -> Self {
Self {
id: Id::random(),
}
}
pub fn with_id(id: Id<Node>) -> Self {
Self {
id,
}
}
pub fn entity_count(&self) -> usize {
todo!()
}
pub fn run() {
todo!()
}
pub fn save(entity_id: impl Into<EntityId>) -> Result<()> {
// TODO
Ok(())
}
// pub fn load(entity_id: impl Into<EntityId>) -> Result<Option<EntityContents>> {
// // TODO
// Ok(None)
// }
}

View file

@ -9,4 +9,5 @@ proc-macro = true
[dependencies]
quote.workspace = true
syn.workspace = true
proc-macro2.workspace = true
proc-macro2.workspace = true
proc-macro-crate.workspace = true

View file

@ -1,4 +1,6 @@
use proc_macro::TokenStream;
use proc_macro_crate::{crate_name, FoundCrate};
use proc_macro2::Span;
use quote::quote;
use syn::parse_quote;
use syn::{DeriveInput, GenericParam, Generics, parse_macro_input};
@ -11,6 +13,15 @@ pub fn vanth_derive(input: TokenStream) -> TokenStream {
let mut generics = input.generics.clone();
let vanth_path = match crate_name("vanth") {
Ok(FoundCrate::Itself) => quote!(crate),
Ok(FoundCrate::Name(name)) => {
let ident = syn::Ident::new(&name, Span::call_site());
quote!(#ident)
}
Err(_) => quote!(vanth),
};
let type_params: Vec<syn::Ident> = generics
.params
.iter()
@ -25,7 +36,7 @@ pub fn vanth_derive(input: TokenStream) -> TokenStream {
let mut where_clause = generics.where_clause.clone().unwrap_or_else(|| parse_quote!(where));
for tp in &type_params {
where_clause.predicates.push(parse_quote!(#tp : vanth::Vanth));
where_clause.predicates.push(parse_quote!(#tp : #vanth_path::Vanth));
}
let (impl_generics, ty_generics, _) = generics.split_for_impl();
@ -34,19 +45,19 @@ pub fn vanth_derive(input: TokenStream) -> TokenStream {
quote! { String::new() }
} else {
quote! {
format!("<{}>", [#(#type_params::ty().path.join("::")),*].join(","))
format!("<{}>", [#( <#type_params as #vanth_path::Vanth>::ty().path.join("::") ),*].join(","))
}
};
let expanded = quote! {
impl #impl_generics vanth::Vanth for #name #ty_generics #where_clause {
fn ty() -> vanth::Ty {
impl #impl_generics #vanth_path::Vanth for #name #ty_generics #where_clause {
fn ty() -> #vanth_path::Ty {
let module_path = module_path!();
let mut path: Vec<String> = module_path.split("::").map(|s| s.to_string()).collect();
let base_name = stringify!(#name);
let generics_str = #generics_code;
path.push(format!("{}{}", base_name, generics_str));
vanth::Ty { path }
#vanth_path::Ty { path }
}
}
};