Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
namse committed Oct 27, 2024
1 parent b47b111 commit 0897ef7
Show file tree
Hide file tree
Showing 9 changed files with 442 additions and 237 deletions.
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions luda-editor/new-server/nsd/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "vvv"
version = "0.1.0"
edition = "2021"

[dependencies]
bytes = "1.8.0"
File renamed without changes.
78 changes: 78 additions & 0 deletions luda-editor/new-server/nsd/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
mod leb128;
mod list;
mod map;

use bytes::Bytes;
use leb128::*;
pub use list::*;
pub use map::*;

pub trait Nsd: Clone {
fn byte_len(&self) -> usize;
fn write_on_bytes(&self, bytes: &mut [u8]) -> usize;
fn from_bytes(bytes: Bytes) -> Self
where
Self: Sized;
fn to_bytes(&self) -> Bytes {
let mut bytes = vec![0u8; self.byte_len()];
self.write_on_bytes(&mut bytes);
Bytes::from(bytes)
}
}

/// Memory layout:
/// - value: [u8; byte_len]
#[derive(Debug, Clone)]
pub struct VStr {
bytes: Bytes,
}

impl From<&str> for VStr {
fn from(s: &str) -> Self {
Self {
bytes: Bytes::copy_from_slice(s.as_bytes()),
}
}
}

impl From<String> for VStr {
fn from(s: String) -> Self {
Self {
bytes: Bytes::from(s.into_bytes()),
}
}
}

impl AsRef<str> for VStr {
fn as_ref(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(&self.bytes) }
}
}

impl std::ops::Deref for VStr {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}

impl Nsd for VStr {
fn byte_len(&self) -> usize {
self.bytes.len()
}

fn write_on_bytes(&self, bytes: &mut [u8]) -> usize {
bytes
.get_mut(0..self.bytes.len())
.unwrap()
.copy_from_slice(&self.bytes);
self.bytes.len()
}

fn from_bytes(bytes: Bytes) -> Self
where
Self: Sized,
{
Self { bytes }
}
}
222 changes: 222 additions & 0 deletions luda-editor/new-server/nsd/src/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
//! # List
//!
//! ## Memory Layout
//!
//! - item count: leb128
//! - item:
//! - item byte len: leb128
//! - item: bytes

use crate::*;

#[derive(Debug, Clone)]
pub struct List<T: Nsd> {
source: Bytes,
source_exclude_indexes: Vec<usize>,
extra: Vec<T>,
}
impl<T: Nsd> List<T> {
pub fn new() -> Self {
Self {
source: Bytes::new(),
source_exclude_indexes: Vec::new(),
extra: Vec::new(),
}
}

pub fn push(&mut self, value: impl Into<T>) {
let value: T = value.into();
self.extra.push(value);
}

pub fn last(&self) -> Option<T> {
if self.extra.is_empty() {
if self.source.is_empty() {
None
} else {
let mut source = self.source.clone();
let item_count = Leb128::read(&mut source);
for index in 0..item_count {
let item_byte_len = Leb128::read(&mut source);
if index == item_count - 1 {
assert_eq!(source.len(), item_byte_len);
let item = T::from_bytes(source.split_to(item_byte_len));
return Some(item);
}
}
assert_eq!(item_count, 0);
None
}
} else {
Some(self.extra.last().unwrap().clone())
}
}

pub fn len(&self) -> usize {
let mut len = self.extra.len();
if !self.source.is_empty() {
let mut source = self.source.clone();
let item_count = Leb128::read(&mut source);
len += item_count;
len -= self.source_exclude_indexes.len();
}
len
}

pub fn is_empty(&self) -> bool {
self.len() == 0
}

pub fn pop(&self) -> Option<T> {
todo!()
}
}

impl<T: Nsd> Nsd for List<T> {
fn byte_len(&self) -> usize {
let mut byte_len = Leb128::new(self.extra.len()).byte_len();
for item in self.extra.iter() {
byte_len += Leb128::new(item.byte_len()).byte_len();
byte_len += item.byte_len();
}
byte_len
}

fn write_on_bytes(&self, bytes: &mut [u8]) -> usize {
let mut index = 0;
index += Leb128::new(self.extra.len()).write_on_bytes(bytes.get_mut(index..).unwrap());
for item in self.extra.iter() {
index += Leb128::new(item.byte_len()).write_on_bytes(bytes.get_mut(index..).unwrap());
index += item.write_on_bytes(bytes.get_mut(index..).unwrap());
}
index
}

fn from_bytes(bytes: Bytes) -> Self
where
Self: Sized,
{
Self {
source: bytes,
source_exclude_indexes: Vec::new(),
extra: Vec::new(),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum IetfLanguageTag {
Ko,
EnUs,
Ja,
}

impl Nsd for IetfLanguageTag {
fn byte_len(&self) -> usize {
std::mem::size_of::<Self>()
}

fn write_on_bytes(&self, bytes: &mut [u8]) -> usize {
bytes[0] = *self as u8;
self.byte_len()
}

fn from_bytes(bytes: Bytes) -> Self
where
Self: Sized,
{
unsafe { std::mem::transmute(bytes[0]) }
}
}

#[test]
fn test_map() {
#[derive(Debug, Clone)]
struct SpeakerDoc {
names: List<VStr>,
}
impl Nsd for SpeakerDoc {
fn byte_len(&self) -> usize {
self.names.byte_len()
}

fn write_on_bytes(&self, bytes: &mut [u8]) -> usize {
let mut index = 0;
index += self.names.write_on_bytes(bytes.get_mut(index..).unwrap());
index
}

fn from_bytes(bytes: Bytes) -> Self
where
Self: Sized,
{
let names = List::from_bytes(bytes);
Self { names }
}
}
let bytes = {
let mut doc = SpeakerDoc { names: List::new() };

let option_value = doc.names.last();
assert!(option_value.is_none());

doc.names.push("안녕하세요");

let option_value = doc.names.last();
assert!(option_value.is_some());

let value: &str = &option_value.unwrap();
assert_eq!(value, "안녕하세요");

assert!(doc.names.len() == 1);

doc.to_bytes()
};

assert_eq!(bytes.len(), 17);

let bytes = {
let doc = SpeakerDoc::from_bytes(bytes);

let option_value = doc.names.last();
assert!(option_value.is_some());
let value: &str = &option_value.unwrap();
assert_eq!(value, "안녕하세요");

let mut doc = doc;

doc.names.pop();

let option_value = doc.names.last();
assert!(option_value.is_none());
assert!(doc.names.is_empty());

doc.names.push("Hello");

let option_value = doc.names.last();
assert!(option_value.is_some());
let value: &str = &option_value.unwrap();
assert_eq!(value, "Hello");

assert_eq!(doc.names.len(), 1);

doc.names.push("World");

let option_value = doc.names.last();
assert!(option_value.is_some());
let value: &str = &option_value.unwrap();
assert_eq!(value, "World");

assert_eq!(doc.names.len(), 2);

doc.to_bytes()
};

assert_eq!(bytes.len(), 23);
}
}
Loading

0 comments on commit 0897ef7

Please sign in to comment.