diff --git a/src/atoms.rs b/src/atoms.rs index 270ebd0..2d66447 100644 --- a/src/atoms.rs +++ b/src/atoms.rs @@ -8,7 +8,22 @@ pub struct RoomId(String); #[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct EventId(String); +#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct ActorId(String); + impl RoomId { + // maybe use the initial create event hash/id as the room id? + pub fn random() -> Self { + let rng = rand::thread_rng() + .sample_iter(Alphanumeric) + .map(char::from) + .take(12) + .collect(); + Self(rng) + } +} + +impl ActorId { pub fn random() -> Self { let rng = rand::thread_rng() .sample_iter(Alphanumeric) @@ -20,6 +35,7 @@ impl RoomId { } impl EventId { + // TEMP: will use hashes pub fn random() -> Self { let rng = rand::thread_rng() .sample_iter(Alphanumeric) @@ -30,26 +46,22 @@ impl EventId { } } -impl Display for RoomId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "!{}", self.0) - } +macro_rules! impl_display { + ($Thing:ty, $fmt:expr) => { + impl Display for $Thing { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, $fmt, self.0) + } + } + + impl Debug for $Thing { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Display::fmt(self, f) + } + } + }; } -impl Display for EventId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "${}", self.0) - } -} - -impl Debug for RoomId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Display::fmt(self, f) - } -} - -impl Debug for EventId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Display::fmt(self, f) - } -} +impl_display!(ActorId, "^{}"); +impl_display!(EventId, "${}"); +impl_display!(RoomId, "!{}"); diff --git a/src/event.rs b/src/event.rs index 5a9b60b..c421bfe 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,8 +1,52 @@ use crate::atoms::EventId; #[derive(Debug)] +/// An event, is the basic building block/envolope containing all data. pub struct Event { pub id: EventId, - pub content: T, + pub content: CoreContent, pub references: Vec, + // pub author: ActorId, + // pub signature: ActorSignature, +} + +#[derive(Debug)] +/// This defines content of an event as either a builtin event or application-specific event. +pub enum CoreContent { + Create(CreateContent), + Custom(T), + + /* + custom events from other places, for inspiration + + ufh (my failed project): + - x.tag{.local} to add tags to events + - x.annotate{.local} to add custom data to events + - x.acl to define access control + - x.update to update/edit events + - x.redact to remove events + - x.file to create new files + + matrix: + - m.room.create to create rooms + - m.room.join_rules to define who can join/leave + - m.room.member to define room members + - m.room.power_levels to define basic access control + - m.room.canonical_alias to add human-readable aliases to rooms + - m.room.redaction to remove events + - m.room.tombstone to replace rooms + - m.space.* for many:many room hierarchies + */ +} + +#[derive(Debug)] +/// Every room has exactly one immutable create event as the single root of the event dag. +pub struct CreateContent { + // TODO: move resolver stuff here +} + +impl CreateContent { + pub fn new() -> Self { + Self { } + } } diff --git a/src/main.rs b/src/main.rs index 12554b9..8416ab4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ +#![allow(dead_code)] // TODO: remove this later! + use std::collections::HashMap; -use crate::{resolver::Resolver, room::Room}; +use crate::{event::CoreContent, resolver::Resolver, room::Room}; mod atoms; mod event; @@ -8,32 +10,31 @@ mod resolver; #[derive(Debug)] enum EventContent { - Create, Set(String, String), } fn main() { let resolver = Resolver::new(Box::new(|events| { + // resolve/reduce state from a sorted list of events, "full resolution" dbg!(events); let mut kv = HashMap::new(); for event in events { match &event.content { - EventContent::Create => {}, - EventContent::Set(k, v) => { + CoreContent::Create(_) => {}, + CoreContent::Custom(EventContent::Set(k, v)) => { kv.insert(k.clone(), v.clone()); }, } } kv }), Box::new(|_a, _b| { + // tiebreak two events todo!() })); - let mut room = Room::new(resolver, EventContent::Create); - room.create_event(EventContent::Set("foo".into(), "apple".into())); - room.create_event(EventContent::Set("bar".into(), "banana".into())); - room.create_event(EventContent::Set("baz".into(), "carrot".into())); + let mut room = Room::new(resolver); + room.create_event(CoreContent::Custom(EventContent::Set("foo".into(), "apple".into()))); + room.create_event(CoreContent::Custom(EventContent::Set("bar".into(), "banana".into()))); + room.create_event(CoreContent::Custom(EventContent::Set("baz".into(), "carrot".into()))); dbg!(&room); - dbg!(&room.get_root()); dbg!(&room.get_state()); - println!("Hello, world!"); } diff --git a/src/resolver.rs b/src/resolver.rs index 19f4dff..1b16515 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -24,26 +24,24 @@ impl Resolver { pub fn sort<'a>(&'a self, events: &'a [Event]) -> Vec<&Event> { let mut references: HashSet<(EventId, EventId)> = events .iter() - .map(|event| { + .flat_map(|event| { event .references .iter() - .map(|r| (r.clone(), event.id.clone())) + .map(|parent_id| (parent_id.clone(), event.id.clone())) }) - .flatten() .collect(); let mut sorted = vec![]; let (mut heads, mut unsorted): (Vec<_>, Vec<_>) = events.iter().partition(|event| event.references.is_empty()); assert!(heads.len() == 1); while let Some(ev) = heads.pop() { - references.retain(|(parent, _)| parent != &ev.id); + references.retain(|(parent_id, _)| parent_id != &ev.id); sorted.push(ev); - let (mut children, new_unsorted) = unsorted.into_iter().partition(|candidate| { + let (new_unsorted, mut children) = unsorted.into_iter().partition(|candidate| { references .iter() - .position(|(_, child)| child == &candidate.id) - .is_none() + .any(|(_, child)| child == &candidate.id) }); unsorted = new_unsorted; children.sort_by(|a, b| (self.tiebreak_fn)(a, b).then_with(|| a.id.cmp(&b.id))); diff --git a/src/room.rs b/src/room.rs index 283635f..3b0dc06 100644 --- a/src/room.rs +++ b/src/room.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; -use crate::{atoms::EventId, event::Event, resolver::Resolver}; +use crate::{atoms::EventId, event::{CoreContent, CreateContent, Event}, resolver::Resolver}; #[derive(Debug)] pub struct Room { @@ -10,11 +10,11 @@ pub struct Room { } impl Room { - pub fn new(resolver: Resolver, base_content: T) -> Self { + pub fn new(resolver: Resolver) -> Self { let event_id = EventId::random(); let base_event = Event { id: event_id.clone(), - content: base_content, + content: CoreContent::Create(CreateContent::new()), references: vec![], }; Self { @@ -25,7 +25,7 @@ impl Room { } pub fn get_root(&self) -> &Event { - self.events.get(0).as_ref().unwrap() + self.events.first().as_ref().unwrap() } pub fn get_state(&mut self) -> S { @@ -34,7 +34,7 @@ impl Room { self.resolver.resolve(&self.events) } - pub fn create_event(&mut self, event_content: T) { + pub fn create_event(&mut self, event_content: CoreContent) { let event = Event { id: EventId::random(), content: event_content,