parent
3818ec7751
commit
ccaaba66d6
@ -1,11 +1,13 @@
|
||||
[package]
|
||||
name = "yuurei"
|
||||
description = "ghost text messaging"
|
||||
description = "ghost text liveboard"
|
||||
version = "0.1.0"
|
||||
authors = ["Avril <flanchan@cumallover.me>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
difference = "2.0.0"
|
||||
futures = "0.3.8"
|
||||
serde = {version = "1.0.118", features=["derive"]}
|
||||
tokio = {version = "0.2", features=["full"] }
|
||||
warp = "0.2.5"
|
||||
|
@ -0,0 +1,257 @@
|
||||
//! Deltas and applying them
|
||||
use super::*;
|
||||
use difference::{
|
||||
Changeset,
|
||||
Difference,
|
||||
};
|
||||
|
||||
const MAX_SINGLE_DELTA_SIZE: usize = 14;
|
||||
const DELTA_BREAK: &str = "";
|
||||
|
||||
/// Infer all deltas needed to be sequentially applied to `orig` to transform it to `new`, return the number inserted into `output`.
|
||||
pub fn infer_deltas<T: BackInserter<Delta> + ?Sized>(output: &mut T, orig: &str, new: &str) -> usize
|
||||
{
|
||||
let set = Changeset::new(orig, new, DELTA_BREAK);
|
||||
|
||||
let mut done=0;
|
||||
let mut position =0;
|
||||
for diff in set.diffs.into_iter() {
|
||||
match diff {
|
||||
Difference::Same(string) => {
|
||||
position += string.len();
|
||||
},
|
||||
Difference::Rem(string) => {
|
||||
output.push_back(Delta {
|
||||
location: position,
|
||||
kind: DeltaKind::RemoveAhead{span_len: string.len()},
|
||||
});
|
||||
done+=1;
|
||||
},
|
||||
Difference::Add(string) => {
|
||||
let mut passer = BackInsertPass::new(|(span, span_len)| {
|
||||
output.push_back(Delta {
|
||||
location: position,
|
||||
kind: DeltaKind::Insert {
|
||||
span, span_len,
|
||||
},
|
||||
});
|
||||
position+= usize::from(span_len);
|
||||
done+=1;
|
||||
});
|
||||
delta_span_many(&mut passer, string.chars());
|
||||
},
|
||||
}
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
/// Create a delta span from an input iterator.
|
||||
///
|
||||
/// This function can take no more than `min(255, MAX_SINGLE_DELTA_SIZE)` chars from the input. The number of chars inserted is also returned as `u8`.
|
||||
pub(super) fn delta_span<I>(from: I) -> ([char; MAX_SINGLE_DELTA_SIZE], u8)
|
||||
where I: IntoIterator<Item = char>
|
||||
{
|
||||
let mut output: [char; MAX_SINGLE_DELTA_SIZE] = Default::default();
|
||||
let mut sz: u8 = 0;
|
||||
|
||||
for (d, s) in output.iter_mut().zip(from.into_iter().take(usize::from(u8::MAX)))
|
||||
{
|
||||
*d = s;
|
||||
sz += 1;
|
||||
}
|
||||
|
||||
(output, sz)
|
||||
}
|
||||
|
||||
/// Create as many delta spans needed from an input iterator.
|
||||
///
|
||||
/// This function can take as many inputs as needed, and outputs the needed amount of spans into `into`, and then returns the number added.
|
||||
pub(super) fn delta_span_many<T: BackInserter<([char; MAX_SINGLE_DELTA_SIZE], u8)> + ?Sized, I>(into: &mut T, from: I) -> usize
|
||||
where I: IntoIterator<Item = char>
|
||||
{
|
||||
let mut iter = from.into_iter();
|
||||
let mut added=0;
|
||||
loop {
|
||||
match delta_span(&mut iter) {
|
||||
(_, 0) => break,
|
||||
other => into.push_back(other),
|
||||
}
|
||||
added+=1;
|
||||
}
|
||||
added
|
||||
}
|
||||
|
||||
/// Information about the delta to be applied in `Delta`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||
pub enum DeltaKind
|
||||
{
|
||||
/// Append to the end of body. Equivilant to `Insert` with a location at `karada.scape.len()` (the end of the buffer).
|
||||
Append{
|
||||
span: [char; MAX_SINGLE_DELTA_SIZE],
|
||||
span_len: u8,
|
||||
},
|
||||
/// Insert `span_len` chars from `span` into body starting *at* `location` and moving ahead
|
||||
Insert{
|
||||
span: [char; MAX_SINGLE_DELTA_SIZE],
|
||||
span_len: u8,
|
||||
},
|
||||
/// Remove `span_len` chars from `location`.
|
||||
RemoveAhead{
|
||||
span_len: usize,
|
||||
},
|
||||
/// Remove `span_len` chars up to but not including `location`.
|
||||
RemoveBehind{
|
||||
span_len: usize,
|
||||
},
|
||||
/// Remove everything from `location` to the end.
|
||||
Truncate,
|
||||
/// Remove everything from 0 to `location`.
|
||||
Shift,
|
||||
/// Remove char at `location`
|
||||
RemoveSingle,
|
||||
/// Remove entire post body
|
||||
Clear,
|
||||
}
|
||||
|
||||
/// A delta to apply to `Karada`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||
pub struct Delta
|
||||
{
|
||||
/// Location to insert into. This is the INclusive range of: 0..=(karada.scape.len()).
|
||||
///
|
||||
/// Insertions off the end of the buffer are to be appened instead.
|
||||
location: usize,
|
||||
/// The kind of delta to insert
|
||||
kind: DeltaKind,
|
||||
}
|
||||
|
||||
/// Static assertion: `MAX_SINGLE_DELTA_SIZE` can fit into `u8`.
|
||||
const _: [u8;(MAX_SINGLE_DELTA_SIZE < (!0u8 as usize)) as usize] = [0];
|
||||
|
||||
impl Delta
|
||||
{
|
||||
/// Apply this delta to a message
|
||||
pub fn insert<T: ?Sized+AsMut<Vec<char>>>(&self, inserter: &mut T)
|
||||
{
|
||||
let inserter = inserter.as_mut();
|
||||
match self.kind {
|
||||
DeltaKind::Append{span, span_len} => {
|
||||
inserter.extend_from_slice(&span[..usize::from(span_len)]);
|
||||
},
|
||||
DeltaKind::Insert{span, span_len} => {
|
||||
let span = &span[..usize::from(span_len)];
|
||||
if self.location == inserter.len() {
|
||||
inserter.extend_from_slice(span);
|
||||
} else if span.len() == 1 {
|
||||
inserter.insert(self.location, span[0]);
|
||||
} else if span.len() > 1 {
|
||||
inserter.insert_exact(self.location, span.iter().copied());
|
||||
}
|
||||
},
|
||||
DeltaKind::RemoveAhead{span_len} => {
|
||||
inserter.drain(self.location..(self.location+span_len));
|
||||
},
|
||||
DeltaKind::RemoveBehind{span_len} => {
|
||||
let span_st = self.location.checked_sub(span_len).unwrap_or(0);
|
||||
inserter.drain(span_st..self.location);
|
||||
},
|
||||
DeltaKind::RemoveSingle => {
|
||||
inserter.remove(self.location);
|
||||
},
|
||||
DeltaKind::Clear => inserter.clear(),
|
||||
DeltaKind::Truncate => inserter.truncate(self.location),
|
||||
DeltaKind::Shift => ((),inserter.drain(..self.location)).0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn infer_and_insert()
|
||||
{
|
||||
let orig = "the quick brown fox jumped over the lazy dog !!!!";
|
||||
let new = "the quick brown dog jumped over the lazy fox twice";
|
||||
|
||||
let mut deltas = Vec::new();
|
||||
infer_deltas(&mut deltas, orig, new);
|
||||
|
||||
println!("{:#?}", deltas);
|
||||
let output: String = {
|
||||
let mut scape: Vec<_> = orig.chars().collect();
|
||||
for delta in deltas.into_iter() {
|
||||
delta.insert(&mut scape);
|
||||
}
|
||||
scape.into_iter().collect()
|
||||
};
|
||||
|
||||
assert_eq!(&output[..], &new[..]);
|
||||
}
|
||||
|
||||
macro_rules! insert {
|
||||
($expects:literal; $start:literal, $ins:literal, $where:expr) => {
|
||||
{
|
||||
|
||||
let mut message: Vec<char> = $start.chars().collect();
|
||||
|
||||
let delta = {
|
||||
let (span, span_len) = delta_span($ins.chars());
|
||||
Delta {
|
||||
location: $where,
|
||||
kind: DeltaKind::Insert{span, span_len},
|
||||
}
|
||||
};
|
||||
|
||||
println!("from: {:?}", message);
|
||||
println!("delta: {:?}", delta);
|
||||
delta.insert(&mut message);
|
||||
|
||||
assert_eq!(&message.into_iter().collect::<String>()[..], $expects);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_body()
|
||||
{
|
||||
insert!("123456789"; "126789", "345", 2);
|
||||
}
|
||||
#[test]
|
||||
fn insert_end()
|
||||
{
|
||||
insert!("123456789"; "1289", "34567", 2);
|
||||
}
|
||||
#[test]
|
||||
fn insert_end_rev()
|
||||
{
|
||||
insert!("123456789"; "1234569", "78", 6);
|
||||
}
|
||||
#[test]
|
||||
fn insert_begin_rev()
|
||||
{
|
||||
insert!("123456789"; "1456789", "23", 1);
|
||||
}
|
||||
#[test]
|
||||
fn insert_begin()
|
||||
{
|
||||
insert!("123456789"; "789", "123456", 0);
|
||||
}
|
||||
#[test]
|
||||
fn insert_end_f()
|
||||
{
|
||||
insert!("123456789"; "123", "456789", 3);
|
||||
}
|
||||
#[test]
|
||||
fn insert_end_f_rev()
|
||||
{
|
||||
insert!("123456789"; "1234567", "89", 7);
|
||||
}
|
||||
#[test]
|
||||
fn insert_single()
|
||||
{
|
||||
insert!("123456789"; "12346789", "5",4);
|
||||
}
|
||||
}
|
@ -0,0 +1,332 @@
|
||||
//! Extensions
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
fmt,
|
||||
ops,
|
||||
};
|
||||
|
||||
/// Wrapper to derive debug for types that don't implement it.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, PartialEq, Eq, Ord,PartialOrd, Hash)]
|
||||
pub struct OpaqueDebug<T>(T);
|
||||
|
||||
impl<T> OpaqueDebug<T>
|
||||
{
|
||||
/// Create a new wrapper
|
||||
#[inline] pub const fn new(value: T) -> Self
|
||||
{
|
||||
Self(value)
|
||||
}
|
||||
|
||||
/// Consume into the value
|
||||
#[inline] pub fn into_inner(self) -> T
|
||||
{
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<T> for OpaqueDebug<T>
|
||||
{
|
||||
#[inline] fn as_ref(&self) -> &T
|
||||
{
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<T> for OpaqueDebug<T>
|
||||
{
|
||||
#[inline] fn as_mut(&mut self) -> &mut T
|
||||
{
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Deref for OpaqueDebug<T>
|
||||
{
|
||||
type Target = T;
|
||||
#[inline] fn deref(&self) -> &Self::Target
|
||||
{
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::DerefMut for OpaqueDebug<T>
|
||||
{
|
||||
#[inline] fn deref_mut(&mut self) -> &mut Self::Target
|
||||
{
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for OpaqueDebug<T>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "<opaque value>")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A trait for types that can insert objects at their end.
|
||||
pub trait BackInserter<T>
|
||||
{
|
||||
/// Insert an object at the end of this container
|
||||
fn push_back(&mut self, value: T);
|
||||
}
|
||||
|
||||
impl<T> BackInserter<T> for Vec<T>
|
||||
{
|
||||
#[inline]
|
||||
fn push_back(&mut self, value: T)
|
||||
{
|
||||
self.push(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Absracts a closure for `BackInserter<T>`.
|
||||
pub struct BackInsertPass<T,F>(F, PhantomData<T>)
|
||||
where F: FnMut(T);
|
||||
|
||||
impl<T,F: FnMut(T)> BackInsertPass<T,F>
|
||||
{
|
||||
/// Create a new instance with this closure
|
||||
#[inline] pub fn new(func: F) -> Self
|
||||
{
|
||||
Self(func, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F: FnMut(T)> BackInserter<T> for BackInsertPass<T,F>
|
||||
{
|
||||
#[inline] fn push_back(&mut self, value: T)
|
||||
{
|
||||
self.0(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// A `BackInserter<T>` that will only add a max capacity of items before it starts dropping input to its `push_back` function.
|
||||
pub struct CappedBackInserter<'a, T>(&'a mut T, usize, usize)
|
||||
where T: BackInserter<T>;
|
||||
|
||||
impl<'a, T> CappedBackInserter<'a, T>
|
||||
where T: BackInserter<T>
|
||||
{
|
||||
/// Create a new instance with this max capacity
|
||||
#[inline] pub fn new(from: &'a mut T, cap: usize) -> Self
|
||||
{
|
||||
Self(from, 0, cap)
|
||||
}
|
||||
|
||||
/// The number of elements pushed so far
|
||||
#[inline] pub fn len(&self) -> usize {
|
||||
self.1
|
||||
}
|
||||
|
||||
/// The max number of elemnts allowed to be pushed
|
||||
#[inline] pub fn cap(&self) -> usize {
|
||||
self.2
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> BackInserter<T> for CappedBackInserter<'a, T>
|
||||
where T: BackInserter<T>
|
||||
{
|
||||
#[inline] fn push_back(&mut self, value: T)
|
||||
{
|
||||
if self.1 < self.2 {
|
||||
self.0.push_back(value);
|
||||
self.1+=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait VecExt<T>
|
||||
{
|
||||
/// Insert many elements with exact size iterator
|
||||
fn insert_exact<Ex, I: IntoIterator<Item = T, IntoIter = Ex>>(&mut self, location: usize, slice: I)
|
||||
where Ex: ExactSizeIterator<Item = T>;
|
||||
|
||||
/// Insert many elements
|
||||
fn insert_many<I: IntoIterator<Item =T>>(&mut self, location: usize, slice: I);
|
||||
}
|
||||
|
||||
|
||||
impl<T> VecExt<T> for Vec<T>
|
||||
{
|
||||
#[cfg(not(feature="experimental_inserter"))]
|
||||
#[inline(always)]
|
||||
fn insert_exact<Ex, I: IntoIterator<Item = T, IntoIter = Ex>>(&mut self, location: usize, slice: I)
|
||||
where Ex: ExactSizeIterator<Item = T>
|
||||
{
|
||||
self.insert_many(location, slice)
|
||||
}
|
||||
#[cfg(feature="experimental_inserter")]
|
||||
fn insert_exact<Ex, I: IntoIterator<Item = T, IntoIter = Ex>>(&mut self, location: usize, slice: I)
|
||||
where Ex: ExactSizeIterator<Item = T>,
|
||||
{
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn panic_len(l1: usize, l2: usize) -> !
|
||||
{
|
||||
panic!("Location must be in range 0..{}, got {}", l1,l2)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn inv_sz() -> !
|
||||
{
|
||||
panic!("ExactSizeIterator returned invalid size");
|
||||
}
|
||||
|
||||
if location >= self.len() {
|
||||
panic_len(self.len(), location);
|
||||
}
|
||||
let mut slice = slice.into_iter();
|
||||
|
||||
let slen = slice.len();
|
||||
match slen {
|
||||
0 => return,
|
||||
1 => {
|
||||
self.insert(location, slice.next().unwrap());
|
||||
return
|
||||
},
|
||||
_ => (),
|
||||
};
|
||||
self.reserve(slice.len());
|
||||
|
||||
unsafe {
|
||||
let this = self.as_mut_ptr().add(location);
|
||||
let len = self.len();
|
||||
let rest = std::mem::size_of::<T>() * (location..len).len();
|
||||
|
||||
libc::memmove(this.add(slen) as *mut libc::c_void, this as *mut libc::c_void, rest);
|
||||
let mut sent=0;
|
||||
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||
let mut this = this;
|
||||
for item in slice {
|
||||
if sent >= slen {
|
||||
inv_sz();
|
||||
}
|
||||
|
||||
this.write(item);
|
||||
this = this.add(1);
|
||||
sent+=1;
|
||||
}
|
||||
if sent != slen {
|
||||
inv_sz();
|
||||
}
|
||||
})) {
|
||||
Err(e) => {
|
||||
// memory at (location+sent)..slen is now invalid, move the old one back before allowing unwind to contine
|
||||
libc::memmove(this.add(sent) as *mut libc::c_void, this.add(slen) as *mut libc::c_void, rest);
|
||||
self.set_len(len + sent);
|
||||
std::panic::resume_unwind(e)
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
self.set_len(len + sent);
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn insert_many<I: IntoIterator<Item =T>>(&mut self, location: usize, slice: I)
|
||||
{
|
||||
let slice = slice.into_iter();
|
||||
match slice.size_hint() {
|
||||
(0, Some(0)) | (0, None) => (),
|
||||
(_, Some(bound)) | (bound, _) => self.reserve(bound),
|
||||
};
|
||||
|
||||
self.splice(location..location, slice);
|
||||
|
||||
//let splice = self.split_off(location);
|
||||
//self.extend(slice.chain(splice.into_iter()));
|
||||
|
||||
/*
|
||||
// shift everything across, replacing with the new values
|
||||
let splice: Vec<_> = self.splice(location.., slice).collect();
|
||||
// ^ -- this allocation bugs me, but we violate aliasing rules if we don't somehow collect it before adding it back in so...
|
||||
// add tail back
|
||||
self.extend(splice);*/
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
use super::*;
|
||||
#[test]
|
||||
fn vec_insert_exact()
|
||||
{
|
||||
let mut vec = vec![0,1,2,8,9,10];
|
||||
vec.insert_exact(3, [3,4,5,6, 7].iter().copied());
|
||||
|
||||
assert_eq!(&vec[..],
|
||||
&[0,1,2,3,4,5,6,7,8,9,10]
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn vec_insert_exact_nt()
|
||||
{
|
||||
macro_rules! string {
|
||||
($str:literal) => (String::from($str));
|
||||
}
|
||||
let mut vec = vec![
|
||||
string!("Hello"),
|
||||
string!("world"),
|
||||
string!("foo"),
|
||||
string!("uhh"),
|
||||
];
|
||||
let vec2 = vec![
|
||||
string!("Hello"),
|
||||
string!("world"),
|
||||
string!("hi"),
|
||||
string!("hello"),
|
||||
string!("foo"),
|
||||
string!("uhh"),
|
||||
];
|
||||
|
||||
vec.insert_exact(2, vec![string!("hi"), string!("hello")]);
|
||||
|
||||
assert_eq!(&vec[..], &vec2[..]);
|
||||
}
|
||||
|
||||
#[cfg(nightly)]
|
||||
mod benchmatks
|
||||
{
|
||||
use super::super::*;
|
||||
use test::{
|
||||
Bencher, black_box,
|
||||
};
|
||||
#[cfg(not(feature="experimental_inserter"))]
|
||||
#[bench]
|
||||
fn move_exact(b: &mut Bencher)
|
||||
{
|
||||
let mut vec = vec![0,10,11,12];
|
||||
let span = [0,1,2,3];
|
||||
b.iter(|| {
|
||||
black_box(vec.insert_exact(vec.len()/2, span.iter().copied()));
|
||||
});
|
||||
}
|
||||
#[bench]
|
||||
fn move_via_splice(b: &mut Bencher)
|
||||
{
|
||||
let mut vec = vec![0,10,11,12];
|
||||
let span = [0,1,2,3];
|
||||
|
||||
b.iter(|| {
|
||||
black_box(vec.insert_many(vec.len()/2, span.iter().copied()));
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature="experimental_inserter")]
|
||||
#[bench]
|
||||
fn move_via_unsafe(b: &mut Bencher)
|
||||
{
|
||||
let mut vec = vec![0,10,11,12];
|
||||
let span = [0,1,2,3];
|
||||
b.iter(|| {
|
||||
black_box(vec.insert_exact(vec.len()/2, span.iter().copied()));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue