-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
442 additions
and
237 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
Oops, something went wrong.