Flesh out store details
This commit is contained in:
parent
e72fd60d16
commit
fb7e504f2c
5 changed files with 183 additions and 88 deletions
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
mod chat;
|
||||
mod store;
|
||||
mod traits;
|
||||
mod ui;
|
||||
|
||||
use toss::terminal::Terminal;
|
||||
|
|
|
|||
|
|
@ -1,86 +1,89 @@
|
|||
pub mod dummy;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use crate::traits::{Msg, MsgStore};
|
||||
pub trait Msg {
|
||||
type Id: Hash + Eq;
|
||||
fn id(&self) -> Self::Id;
|
||||
fn parent(&self) -> Option<Self::Id>;
|
||||
|
||||
pub struct DummyMsg {
|
||||
id: usize,
|
||||
parent: Option<usize>,
|
||||
time: DateTime<Utc>,
|
||||
nick: String,
|
||||
content: String,
|
||||
fn time(&self) -> DateTime<Utc>;
|
||||
fn nick(&self) -> String;
|
||||
fn content(&self) -> String;
|
||||
}
|
||||
|
||||
impl DummyMsg {
|
||||
pub fn new<S>(id: usize, nick: S, content: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
pub struct Path<I>(Vec<I>);
|
||||
|
||||
impl<I> Path<I> {
|
||||
pub fn new(segments: Vec<I>) -> Self {
|
||||
assert!(!segments.is_empty(), "segments must not be empty");
|
||||
Self(segments)
|
||||
}
|
||||
|
||||
pub fn segments(&self) -> &[I] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn first(&self) -> &I {
|
||||
self.0.first().expect("path is not empty")
|
||||
}
|
||||
|
||||
pub fn first_mut(&mut self) -> &mut I {
|
||||
self.0.first_mut().expect("path is not empty")
|
||||
}
|
||||
|
||||
pub fn last(&self) -> &I {
|
||||
self.0.last().expect("path is not empty")
|
||||
}
|
||||
|
||||
pub fn last_mut(&mut self) -> &mut I {
|
||||
self.0.last_mut().expect("path is not empty")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Tree<M: Msg> {
|
||||
root: M::Id,
|
||||
msgs: HashMap<M::Id, M>,
|
||||
children: HashMap<M::Id, Vec<M::Id>>,
|
||||
}
|
||||
|
||||
impl<M: Msg> Tree<M> {
|
||||
pub fn new(root: M::Id, msgs: Vec<M>) -> Self {
|
||||
let msgs: HashMap<M::Id, M> = msgs.into_iter().map(|m| (m.id(), m)).collect();
|
||||
|
||||
let mut children: HashMap<M::Id, Vec<M::Id>> = HashMap::new();
|
||||
for msg in msgs.values() {
|
||||
if let Some(parent) = msg.parent() {
|
||||
children.entry(parent).or_default().push(msg.id());
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
id,
|
||||
parent: None,
|
||||
time: Utc.timestamp(0, 0),
|
||||
nick: nick.into(),
|
||||
content: content.into(),
|
||||
root,
|
||||
msgs,
|
||||
children,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent(mut self, parent: usize) -> Self {
|
||||
self.parent = Some(parent);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Msg for DummyMsg {
|
||||
type Id = usize;
|
||||
|
||||
fn id(&self) -> Self::Id {
|
||||
self.id
|
||||
pub fn root(&self) -> &M::Id {
|
||||
&self.root
|
||||
}
|
||||
|
||||
fn time(&self) -> DateTime<Utc> {
|
||||
self.time
|
||||
pub fn msg(&self, id: &M::Id) -> Option<&M> {
|
||||
self.msgs.get(id)
|
||||
}
|
||||
|
||||
fn nick(&self) -> String {
|
||||
self.nick.clone()
|
||||
}
|
||||
|
||||
fn content(&self) -> String {
|
||||
self.content.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DummyStore {
|
||||
msgs: HashMap<usize, DummyMsg>,
|
||||
}
|
||||
|
||||
impl DummyStore {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
msgs: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn msg(mut self, msg: DummyMsg) -> Self {
|
||||
self.msgs.insert(msg.id(), msg);
|
||||
self
|
||||
pub fn children(&self, id: &M::Id) -> Option<&[M::Id]> {
|
||||
self.children.get(id).map(|c| c as &[M::Id])
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl MsgStore<DummyMsg> for DummyStore {
|
||||
async fn path(&self, _room: &str, mut id: usize) -> Vec<usize> {
|
||||
let mut path = vec![id];
|
||||
|
||||
while let Some(parent) = self.msgs.get(&id).and_then(|msg| msg.parent) {
|
||||
path.push(parent);
|
||||
id = parent;
|
||||
}
|
||||
|
||||
path.reverse();
|
||||
path
|
||||
}
|
||||
pub trait MsgStore<M: Msg> {
|
||||
async fn path(&self, room: &str, id: M::Id) -> Path<M::Id>;
|
||||
async fn thread(&self, room: &str, root: M::Id) -> Tree<M>;
|
||||
}
|
||||
|
|
|
|||
112
cove-tui/src/store/dummy.rs
Normal file
112
cove-tui/src/store/dummy.rs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
use std::collections::HashMap;
|
||||
use std::thread::Thread;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
|
||||
use super::{Msg, MsgStore, Path, Tree};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DummyMsg {
|
||||
id: usize,
|
||||
parent: Option<usize>,
|
||||
time: DateTime<Utc>,
|
||||
nick: String,
|
||||
content: String,
|
||||
}
|
||||
|
||||
impl DummyMsg {
|
||||
pub fn new<S>(id: usize, nick: S, content: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self {
|
||||
id,
|
||||
parent: None,
|
||||
time: Utc.timestamp(0, 0),
|
||||
nick: nick.into(),
|
||||
content: content.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent(mut self, parent: usize) -> Self {
|
||||
self.parent = Some(parent);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Msg for DummyMsg {
|
||||
type Id = usize;
|
||||
|
||||
fn id(&self) -> Self::Id {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Self::Id> {
|
||||
self.parent
|
||||
}
|
||||
|
||||
fn time(&self) -> DateTime<Utc> {
|
||||
self.time
|
||||
}
|
||||
|
||||
fn nick(&self) -> String {
|
||||
self.nick.clone()
|
||||
}
|
||||
|
||||
fn content(&self) -> String {
|
||||
self.content.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DummyStore {
|
||||
msgs: HashMap<usize, DummyMsg>,
|
||||
children: HashMap<usize, Vec<usize>>,
|
||||
}
|
||||
|
||||
impl DummyStore {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
msgs: HashMap::new(),
|
||||
children: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn msg(mut self, msg: DummyMsg) -> Self {
|
||||
if let Some(parent) = msg.parent {
|
||||
self.children.entry(parent).or_default().push(msg.id());
|
||||
}
|
||||
self.msgs.insert(msg.id(), msg);
|
||||
self
|
||||
}
|
||||
|
||||
fn tree(&self, id: usize, result: &mut Vec<DummyMsg>) {
|
||||
if let Some(msg) = self.msgs.get(&id) {
|
||||
result.push(msg.clone());
|
||||
if let Some(children) = self.children.get(&id) {
|
||||
for child in children {
|
||||
self.tree(*child, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl MsgStore<DummyMsg> for DummyStore {
|
||||
async fn path(&self, _room: &str, mut id: usize) -> Path<usize> {
|
||||
let mut segments = vec![id];
|
||||
while let Some(parent) = self.msgs.get(&id).and_then(|msg| msg.parent) {
|
||||
segments.push(parent);
|
||||
id = parent;
|
||||
}
|
||||
segments.reverse();
|
||||
Path::new(segments)
|
||||
}
|
||||
|
||||
async fn thread(&self, _room: &str, root: usize) -> Tree<DummyMsg> {
|
||||
let mut msgs = vec![];
|
||||
|
||||
Tree::new(root, msgs)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
pub trait Msg {
|
||||
type Id;
|
||||
fn id(&self) -> Self::Id;
|
||||
|
||||
fn time(&self) -> DateTime<Utc>;
|
||||
fn nick(&self) -> String;
|
||||
fn content(&self) -> String;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait MsgStore<M: Msg> {
|
||||
async fn path(&self, room: &str, id: M::Id) -> Vec<M::Id>;
|
||||
}
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
use std::collections::hash_map::Entry;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::Duration;
|
||||
|
||||
use crossterm::event::{Event, EventStream, KeyCode, KeyEvent, MouseEvent};
|
||||
use crossterm::style::ContentStyle;
|
||||
use futures::StreamExt;
|
||||
use crossterm::event::{Event, KeyCode, KeyEvent, MouseEvent};
|
||||
use parking_lot::FairMutex;
|
||||
use tokio::sync::mpsc::error::TryRecvError;
|
||||
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||
|
|
@ -13,7 +10,7 @@ use toss::frame::{Frame, Pos, Size};
|
|||
use toss::terminal::Terminal;
|
||||
|
||||
use crate::chat::Chat;
|
||||
use crate::store::{DummyMsg, DummyStore};
|
||||
use crate::store::dummy::{DummyMsg, DummyStore};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UiEvent {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue