use std::collections::BTreeSet;
use futures_util::TryStreamExt;
use macro_rules_attribute::apply;
use object_rainbow::{
InlineOutput, ListHashes, MaybeHasNiche, Parse, ParseInline, Size, Tagged, ToOutput,
Topological,
};
use object_rainbow_history::{
FromIter, Parallel, Return, Sequential,
remap::{MapToSet, MappedToSet},
};
use object_rainbow_trie::{TrieMap, TrieSet};
use smol_macros::main;
use ulid::Ulid;
#[derive(
Debug,
ToOutput,
InlineOutput,
Tagged,
ListHashes,
Topological,
Parse,
ParseInline,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Size,
MaybeHasNiche,
)]
struct ChannelId(Ulid);
#[derive(
Debug,
ToOutput,
InlineOutput,
Tagged,
ListHashes,
Topological,
Parse,
ParseInline,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Size,
MaybeHasNiche,
)]
struct MessageId(Ulid);
#[derive(
Debug,
ToOutput,
InlineOutput,
Tagged,
ListHashes,
Topological,
Parse,
ParseInline,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Size,
MaybeHasNiche,
)]
struct UserId(Ulid);
#[derive(
ToOutput,
InlineOutput,
Tagged,
ListHashes,
Topological,
Parse,
ParseInline,
Clone,
Copy,
PartialEq,
Eq,
Size,
MaybeHasNiche,
)]
struct Message {
channel: ChannelId,
user: UserId,
}
#[derive(
Debug,
ToOutput,
InlineOutput,
Tagged,
ListHashes,
Topological,
Parse,
ParseInline,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
)]
struct MessageByChannel {
channel: ChannelId,
message: MessageId,
user: UserId,
}
#[derive(
Debug,
ToOutput,
InlineOutput,
Tagged,
ListHashes,
Topological,
Parse,
ParseInline,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
)]
struct MessageByUser {
user: UserId,
channel: ChannelId,
message: MessageId,
}
#[derive(
ToOutput,
InlineOutput,
Tagged,
ListHashes,
Topological,
Parse,
ParseInline,
Clone,
Copy,
PartialEq,
Eq,
Default,
)]
struct MessageToChannel;
#[derive(
ToOutput,
InlineOutput,
Tagged,
ListHashes,
Topological,
Parse,
ParseInline,
Clone,
Copy,
PartialEq,
Eq,
Default,
)]
struct MessageToUser;
impl MapToSet<MessageId, Message> for MessageToChannel {
type T = MessageByChannel;
fn map(
&self,
message: MessageId,
Message { channel, user }: Message,
) -> impl Send + Future<Output = object_rainbow::Result<Self::T>> {
async move {
Ok(MessageByChannel {
channel,
message,
user,
})
}
}
}
impl MapToSet<MessageId, Message> for MessageToUser {
type T = MessageByUser;
fn map(
&self,
message: MessageId,
Message { channel, user }: Message,
) -> impl Send + Future<Output = object_rainbow::Result<Self::T>> {
async move {
Ok(MessageByUser {
user,
channel,
message,
})
}
}
}
type MessagesByChannels =
Sequential<MappedToSet<MessageToChannel>, FromIter<TrieSet<MessageByChannel>>>;
type MessagesByUsers = Sequential<MappedToSet<MessageToUser>, FromIter<TrieSet<MessageByUser>>>;
type Tree = Sequential<
Parallel<TrieMap<MessageId, Message>, Return>,
Parallel<MessagesByChannels, MessagesByUsers>,
>;
type Diff = (Option<Message>, MessageId);
type History = object_rainbow_history::History<Tree, Diff>;
trait Table {
fn messages_by_channels(
&self,
) -> impl Send + Future<Output = object_rainbow::Result<TrieSet<MessageByChannel>>>;
fn messages_by_users(
&self,
) -> impl Send + Future<Output = object_rainbow::Result<TrieSet<MessageByUser>>>;
fn insert(
&mut self,
message: MessageId,
contents: Message,
) -> impl Send + Future<Output = object_rainbow::Result<()>>;
fn delete(
&mut self,
message: MessageId,
) -> impl Send + Future<Output = object_rainbow::Result<()>>;
}
impl Table for History {
fn messages_by_channels(
&self,
) -> impl Send + Future<Output = object_rainbow::Result<TrieSet<MessageByChannel>>> {
async move { Ok(self.tree().await?.second().a().second().0.clone()) }
}
fn messages_by_users(
&self,
) -> impl Send + Future<Output = object_rainbow::Result<TrieSet<MessageByUser>>> {
async move { Ok(self.tree().await?.second().b().second().0.clone()) }
}
fn insert(
&mut self,
message: MessageId,
contents: Message,
) -> impl Send + Future<Output = object_rainbow::Result<()>> {
self.commit((Some(contents), message))
}
fn delete(
&mut self,
message: MessageId,
) -> impl Send + Future<Output = object_rainbow::Result<()>> {
self.commit((None, message))
}
}
#[apply(main!)]
async fn main() -> object_rainbow::Result<()> {
let mut history = History::new();
let channel = ChannelId(Ulid::new());
let user = UserId(Ulid::new());
let message = MessageId(Ulid::new());
history.insert(message, Message { channel, user }).await?;
assert!(
history
.messages_by_channels()
.await?
.contains(&MessageByChannel {
channel,
message,
user,
})
.await?,
);
assert!(
history
.messages_by_users()
.await?
.contains(&MessageByUser {
user,
channel,
message,
})
.await?,
);
let messages_by_channel = history
.messages_by_channels()
.await?
.range_stream(
&MessageByChannel {
channel,
message: MessageId(Ulid::from_parts(u64::MIN, u128::MIN)),
user: UserId(Ulid::from_parts(u64::MIN, u128::MIN)),
}..=&MessageByChannel {
channel,
message: MessageId(Ulid::from_parts(u64::MAX, u128::MAX)),
user: UserId(Ulid::from_parts(u64::MAX, u128::MAX)),
},
)
.try_collect::<BTreeSet<_>>()
.await?;
assert_eq!(
messages_by_channel,
BTreeSet::from([MessageByChannel {
channel,
message,
user,
}]),
);
history.delete(message).await?;
assert!(
!history
.messages_by_channels()
.await?
.contains(&MessageByChannel {
channel,
message,
user,
})
.await?,
);
assert!(
!history
.messages_by_users()
.await?
.contains(&MessageByUser {
user,
channel,
message,
})
.await?,
);
Ok(())
}