parent
3818ec7751
commit
ccaaba66d6
@ -1,11 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "yuurei"
|
name = "yuurei"
|
||||||
description = "ghost text messaging"
|
description = "ghost text liveboard"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Avril <flanchan@cumallover.me>"]
|
authors = ["Avril <flanchan@cumallover.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
difference = "2.0.0"
|
||||||
futures = "0.3.8"
|
futures = "0.3.8"
|
||||||
|
serde = {version = "1.0.118", features=["derive"]}
|
||||||
tokio = {version = "0.2", features=["full"] }
|
tokio = {version = "0.2", features=["full"] }
|
||||||
warp = "0.2.5"
|
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