legacy
Avril 4 years ago
parent b555b10657
commit f8adf9721a
Signed by: flanchan
GPG Key ID: 284488987C31F630

8
Cargo.lock generated

@ -38,6 +38,12 @@ dependencies = [
"generic-array",
]
[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]]
name = "bytes"
version = "0.5.6"
@ -594,8 +600,10 @@ name = "yuurei"
version = "0.1.0"
dependencies = [
"async-trait",
"byteorder",
"chrono",
"cryptohelpers",
"libc",
"once_cell",
"rustc_version",
"tokio",

@ -13,6 +13,8 @@ chrono = "0.4.15"
uuid = {version = "0.8", features=["v4"]}
once_cell = "1.4.1"
crypto = {package= "cryptohelpers", version = "0.1", features= ["async", "sha256"]}
libc = "0.2.76"
byteorder = "1.3.4"
[build-dependencies]
rustc_version = "0.2"

@ -1,4 +1,8 @@
use std::{
fmt,
error,
};
use libc::c_void;
pub unsafe fn refer<'a, T>(src: &'a T) -> &'a [u8]
where T: ?Sized
@ -24,3 +28,79 @@ pub unsafe fn derefer_mut<'a, T>(src: &'a mut [u8]) -> &'a mut T
&mut *(&mut src[0] as *mut u8 as *mut T)
}
/// Represents a type that can be converted from bytes to itself
pub trait FromBytes: Sized
{
type Error;
fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self,Self::Error>;
}
/// Represents a type that can be converted into bytes
pub trait IntoBytes:Sized
{
fn into_bytes(self) -> Box<[u8]>;
}
impl<T: Into<Box<[u8]>>> IntoBytes for T
{
#[inline] fn into_bytes(self) -> Box<[u8]>
{
self.into()
}
}
impl FromBytes for Vec<u8>
{
type Error = !;
#[inline] fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self,Self::Error>
{
Ok(Vec::from(bytes.as_ref()))
}
}
impl FromBytes for Box<[u8]>
{
type Error = !;
#[inline] fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self,Self::Error>
{
Ok(Vec::from(bytes.as_ref()).into_boxed_slice())
}
}
/// The error used when a `FromBytes` conversion fails because the buffer was not the correct size
#[derive(Debug)]
pub struct SizeError;
impl error::Error for SizeError{}
impl fmt::Display for SizeError
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f,"buffer was not the correct size")
}
}
/// Copy slice of bytes only
///
/// # Notes
/// `dst` and `src` must not overlap. See [move_slice].
pub fn copy_slice(dst: &mut [u8], src: &[u8]) -> usize
{
let sz = std::cmp::min(dst.len(),src.len());
unsafe {
libc::memcpy(&mut dst[0] as *mut u8 as *mut c_void, &src[0] as *const u8 as *const c_void, sz);
}
sz
}
/// Move slice of bytes only
///
/// # Notes
/// `dst` and `src` can overlap.
pub fn move_slice(dst: &mut [u8], src: &[u8]) -> usize
{
let sz = std::cmp::min(dst.len(),src.len());
unsafe {
libc::memmove(&mut dst[0] as *mut u8 as *mut c_void, &src[0] as *const u8 as *const c_void, sz);
}
sz
}

@ -9,6 +9,29 @@ use uuid::Uuid;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct PostID(Uuid);
impl bytes::IntoBytes for PostID
{
fn into_bytes(self) -> Box<[u8]>
{
Box::from(*self.0.as_bytes())
}
}
impl bytes::FromBytes for PostID
{
type Error = bytes::SizeError;
fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self,Self::Error> {
let bytes = bytes.as_ref();
if bytes.len() < 16 {
Err(bytes::SizeError)
} else {
let by = [0u8; 16];
assert_eq!(bytes::copy_slice(&mut by[..], bytes), 16);
Ok(Self(Uuid::from_bytes(by)))
}
}
}
impl PostID
{
/// Generate a new `PostID`.

@ -5,6 +5,13 @@
use async_trait::async_trait;
use self::{
bytes::{
FromBytes as _,
IntoBytes as _,
},
};
mod bytes;
mod suspend;

@ -20,6 +20,54 @@ where T: TimeZone,
pub last_edit: DateTime<T>,
}
impl<T> bytes::IntoBytes for PostTimestamp<T>
where T: TimeZone,
{
fn into_bytes(self) -> Box<[u8]> {
const ESIZE: usize = std::mem::size_of::<i64>();
let mut output =[0u8; ESIZE * 3];
use byteorder::{
LittleEndian,
WriteBytesExt,
};
//FUCK this. why is ther eno from_timestamp_nanos()!??? wtf is the point of the nanos versions then?????? fuck
output[..ESIZE] .as_mut().write_i64::<LittleEndian>(self.opened.timestamp()).unwrap();
output[ESIZE..ESIZE*2] .as_mut().write_i64::<LittleEndian>(self.closed.map(|x| x.timestamp()).unwrap_or(i64::MIN)).unwrap();
output[ESIZE*2..ESIZE*3].as_mut().write_i64::<LittleEndian>(self.last_edit.timestamp()).unwrap();
output.into()
}
}
impl bytes::FromBytes for PostTimestamp
{
type Error = bytes::SizeError;
fn from_bytes<U: AsRef<[u8]>>(bytes: U) -> Result<Self,Self::Error> {
const ESIZE: usize = std::mem::size_of::<i64>();
let bytes=bytes.as_ref();
if bytes.len() < ESIZE * 3 {
return Err(bytes::SizeError);
}
use byteorder::{
LittleEndian,
ReadBytesExt,
};
let opened = bytes.read_i64::<LittleEndian>().unwrap();
let closed = match bytes[ESIZE..].as_ref().read_i64::<LittleEndian>().unwrap() {
i64::MIN => None,
x => Some(x),
};
let last_edit = bytes[ESIZE*2..].as_ref().read_i64::<LittleEndian>().unwrap();
Ok(Self{
opened: DateTime::from_utc(NaiveDateTime::from_timestamp(opened, 0), Utc),
closed: closed.map(|closed| DateTime::from_utc(NaiveDateTime::from_timestamp(closed, 0), Utc)),
last_edit: DateTime::from_utc(NaiveDateTime::from_timestamp(last_edit, 0), Utc),
})
}
}
impl<Tz: TimeZone> Hash for PostTimestamp<Tz> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.opened.hash(state);
@ -62,3 +110,38 @@ pub struct Static
/// Hash of the rest of the post data. . . .
hash: crypto::sha256::Sha256Hash,
}
use suspend::{
Suspendable,
SuspendStream,
};
#[async_trait]
impl Suspendable for Static
{
async fn suspend<S: SuspendStream +Send+Sync + ?Sized>(self, into: &mut S) -> Result<(), suspend::Error>
{
let mut output = suspend::Object::new();
output.insert_value("id", self.id);
output.insert_bool("Some(user-name)", self.user.name.is_some());
output.insert_string("user-name", self.user.name.unwrap_or_default());
output.insert_bool("Some(user-email)", self.user.email.is_some());
output.insert_string("user-email", self.user.email.unwrap_or_default());
//TODO: Tripcode
output.insert_bool("Some(title)", self.title.is_some());
output.insert_string("title", self.title.unwrap_or_default());
output.insert_string("body", self.karada);
output.insert_value("timestamp", self.timestamp);
output.insert_bytes("hash", self.hash);
into.set_object(output).await
}
async fn load<S: SuspendStream +Send+Sync+ ?Sized>(from: &mut S) -> Result<Self, suspend::Error>
{
fuck
todo!() //ehhhh... this is so dumb...
}
}

@ -1,5 +1,8 @@
//! Handles updating posts
use super::*;
use std::{
sync::Arc,
};
use tokio::{
sync::{
RwLock,
@ -60,9 +63,9 @@ const _: [u8;(MAX_SINGLE_DELTA_SIZE < (!0u8 as usize)) as usize] = [0];
pub struct Karada
{
/// The post body so far as a vector of `char`s.
scape: RwLock<Vec<char>>,
scape: Arc<RwLock<Vec<char>>>,
/// All applied deltas so far. Last applied one is at the end.
deltas: RwLock<Vec<Delta>>,
deltas: Arc<RwLock<Vec<Delta>>>,
/// the latest render of the whole body string. Updated whenever a delta(s) are applied atomically.
current_body: watch::Receiver<String>,

@ -4,6 +4,8 @@ use std::{
marker::{
PhantomData,
Unpin,
Send,
Sync,
},
io,
collections::HashMap,
@ -22,10 +24,14 @@ use tokio::{
AsyncWrite,
},
};
use bytes::{
IntoBytes,
FromBytes,
};
/// Represents an opaque bytes stream of serialised data to insert into `SuspendStream`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SuspendObject
pub struct Object
{
data: Vec<u8>,
data_instances: HashMap<Cow<'static, str>, Range<usize>>,
@ -48,9 +54,9 @@ where I: IntoIterator<Item = T>,
max
}
impl SuspendObject
impl Object
{
/// Create a new empty `SuspendObject`.
/// Create a new empty `Object`.
#[inline] pub fn new() -> Self
{
Self{data: Vec::new(), data_instances: HashMap::new()}
@ -68,6 +74,45 @@ impl SuspendObject
true
}
/// Insert a boolean
pub fn insert_bool(&mut self, name: impl Into<Cow<'static, str>>, value: bool)
{
self.insert_bytes(name, if value {&[1]} else {&[0]})
}
/// Get a boolean
pub fn get_bool(&self, name: impl Borrow<str>) -> Option<bool>
{
self.get_bytes(name).map(|x| if x[0]==0 {false} else {true})
}
/// Insert a UTF-8 string
pub fn insert_string(&mut self, name: impl Into<Cow<'static, str>>, stri: impl AsRef<str>)
{
self.insert_bytes(name, stri.as_ref().as_bytes())
}
/// Try to get a UTF-8 string, returning `None` if either the name was not present, or the string was not formatted correctly
pub fn try_get_string(&self, name: impl Borrow<str>) -> Option<&str>
{
if let Some(bytes) = self.get_bytes(name) {
std::str::from_utf8(bytes).ok()
} else {
None
}
}
/// Try to get a UTF-8 string, returning `None` if the name was not present
///
/// # Panics
/// If the present string was not valid UTF-8
pub fn get_string(&self, name: impl Borrow<str>) -> Option<&str>
{
if let Some(bytes) = self.get_bytes(name) {
Some(std::str::from_utf8(bytes).expect("String contained invalid UTF-8"))
} else {
None
}
}
/// Insert bytes directly with this name
pub fn insert_bytes(&mut self, name: impl Into<Cow<'static, str>>, bytes: impl AsRef<[u8]>)
{
@ -80,13 +125,32 @@ impl SuspendObject
}
/// Insert a value's bytes directly with this name
pub unsafe fn insert_value<T,U>(&mut self, name: U, value: &T)
pub unsafe fn insert_value_raw<T,U>(&mut self, name: U, value: &T)
where T: ?Sized,
U: Into<Cow<'static, str>>
{
self.insert_bytes(name, bytes::refer(value))
}
/// Convert a value to bytes and insert it into this object
pub fn insert_value<T: IntoBytes, U>(&mut self, name: U, value: T)
where U: Into<Cow<'static, str>>
{
self.insert_bytes(name, value.into_bytes())
}
/// Try to get a value from the bytes specified by name
pub fn get_value<T>(&self, name: impl Borrow<str>) -> Result<Option<T>, T::Error>
where T: FromBytes
{
if let Some(range) = self.data_instances.get(name.borrow()) {
Ok(Some(T::from_bytes(&self.data[range.clone()])?))
} else {
Ok(None)
}
}
/// Try to get the bytes specified by name
pub fn get_bytes(&self, name: impl Borrow<str>) -> Option<&[u8]>
{
@ -101,13 +165,13 @@ impl SuspendObject
///
/// # Panics
/// If `T` cannot fit into the size of the range
pub unsafe fn get_value<T>(&self, name: impl Borrow<str>) -> Option<&T>
pub unsafe fn get_value_raw<T>(&self, name: impl Borrow<str>) -> Option<&T>
{
self.get_bytes(name).map(|x| bytes::derefer(x))
}
/// Try to get the value specified by name. Will return `None` if `T` cannot fit in the returned bytes.
pub unsafe fn try_get_value<T>(&self, name: impl Borrow<str>) -> Option<&T>
pub unsafe fn try_get_value_raw<T>(&self, name: impl Borrow<str>) -> Option<&T>
{
if let Some(bytes) = self.get_bytes(name) {
if bytes.len() >= std::mem::size_of::<T>() {
@ -249,22 +313,22 @@ impl SuspendObject
pub trait SuspendStream
{
/// Write an object into the opaque stream.
async fn set_object(&mut self, obj: SuspendObject) -> Result<(), SuspendError>;
async fn set_object(&mut self, obj: Object) -> Result<(), Error>;
/// Read an object from the opaque stream.
async fn get_object(&mut self) -> Result<Option<SuspendObject>, SuspendError>;
async fn get_object(&mut self) -> Result<Option<Object>, Error>;
}
/// An error that occoured in a suspend operation
#[derive(Debug)]
#[non_exhaustive]
pub enum SuspendError {
pub enum Error {
BadObject,
Corruption,
IO(io::Error),
Unknown,
}
impl error::Error for SuspendError
impl error::Error for Error
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(match &self {
@ -273,7 +337,7 @@ impl error::Error for SuspendError
})
}
}
impl fmt::Display for SuspendError
impl fmt::Display for Error
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
@ -291,14 +355,15 @@ impl fmt::Display for SuspendError
#[async_trait]
pub trait Suspendable: Sized
{
async fn suspend<S: SuspendStream + ?Sized>(self, into: &mut S) -> Result<(), SuspendError>;
async fn load<S: SuspendStream + ?Sized>(from: &mut S) -> Result<Self, SuspendError>;
async fn suspend<S: SuspendStream + Send + Sync+ ?Sized>(self, into: &mut S) -> Result<(), Error>;
async fn load<S: SuspendStream + Send+ Sync+?Sized>(from: &mut S) -> Result<Self, Error>;
}
/*
pub struct SuspenceState<T>
where T: Suspendable
{
_phantom: PhantomData<T>,
}*/

Loading…
Cancel
Save