Skip to content

Commit

Permalink
feat: crdt type create & convert (#461)
Browse files Browse the repository at this point in the history
* feat: add convert for any

* chore: disable add to project action

* feat: add content convert & sub array support

* feat: fix item ref for ytype

* fix: test case

* chore: cleanup type convertor
  • Loading branch information
darkskygit authored Jun 14, 2023
1 parent 6b584a2 commit 4273316
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 106 deletions.
40 changes: 20 additions & 20 deletions .github/workflows/add-to-project.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
name: Add to GitHub projects

on:
issues:
types:
- opened
pull_request_target:
types:
- opened
- reopened
# on:
# issues:
# types:
# - opened
# pull_request_target:
# types:
# - opened
# - reopened

jobs:
add-to-project:
name: Add issues and pull requests
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
with:
# You can target a repository in a different organization
# to the issue
project-url: https://github.com/orgs/toeverything/projects/10
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
# labeled: bug, needs-triage
# label-operator: OR
add-to-project:
name: Add issues and pull requests
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
with:
# You can target a repository in a different organization
# to the issue
project-url: https://github.com/orgs/toeverything/projects/10
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
# labeled: bug, needs-triage
# label-operator: OR
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion libs/jwst-codec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ arbitrary = { version = "1.3.0", features = ["derive"] }
ordered-float = { version = "3.6.0", features = ["arbitrary"] }

[dev-dependencies]
assert-json-diff = "2.0.2"
criterion = { version = "0.5.1", features = ["html_reports"] }
lib0 = "0.16.5"
lib0 = { version = "0.16.5", features = ["lib0-serde"] }
ordered-float = { version = "3.6.0", features = ["proptest"] }
path-ext = "0.1.0"
proptest = "1.1.0"
Expand Down
221 changes: 156 additions & 65 deletions libs/jwst-codec/src/doc/codec/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,112 +112,142 @@ impl<W: CrdtWriter> CrdtWrite<W> for Any {
}
}

// TODO: impl for Any::Undefined
impl From<String> for Any {
fn from(s: String) -> Self {
Any::String(s)
impl Any {
fn read_key_value<R: CrdtReader>(reader: &mut R) -> JwstCodecResult<(String, Any)> {
let key = reader.read_var_string()?;
let value = Self::read(reader)?;

Ok((key, value))
}
}

impl From<&str> for Any {
fn from(s: &str) -> Self {
Any::from(s.to_string())
fn write_key_value<W: CrdtWriter>(writer: &mut W, key: &str, value: &Any) -> JwstCodecResult {
writer.write_var_string(key)?;
value.write(writer)?;

Ok(())
}
}

impl<T: Into<Any>> From<Option<T>> for Any {
fn from(value: Option<T>) -> Self {
if let Some(val) = value {
val.into()
} else {
Any::Null
}
pub(crate) fn read_multiple<R: CrdtReader>(reader: &mut R) -> JwstCodecResult<Vec<Any>> {
let len = reader.read_var_u64()?;
let any = (0..len)
.map(|_| Any::read(reader))
.collect::<Result<Vec<_>, _>>()?;

Ok(any)
}
}

impl From<u64> for Any {
fn from(value: u64) -> Self {
Any::Integer(value)
pub(crate) fn write_multiple<W: CrdtWriter>(writer: &mut W, any: &[Any]) -> JwstCodecResult {
writer.write_var_u64(any.len() as u64)?;
for value in any {
value.write(writer)?;
}

Ok(())
}
}

impl From<OrderedFloat<f32>> for Any {
fn from(value: OrderedFloat<f32>) -> Self {
Any::Float32(value)
}
macro_rules! impl_primitive_from {
(unsigned, $($ty: ty),*) => {
$(
impl From<$ty> for Any {
fn from(value: $ty) -> Self {
Self::Integer(value.into())
}
}
)*
};
(signed, $($ty: ty),*) => {
$(
impl From<$ty> for Any {
fn from(value: $ty) -> Self {
Self::BigInt64(value.into())
}
}
)*
};
(string, $($ty: ty),*) => {
$(
impl From<$ty> for Any {
fn from(value: $ty) -> Self {
Self::String(value.into())
}
}
)*
};
}

impl From<OrderedFloat<f64>> for Any {
fn from(value: OrderedFloat<f64>) -> Self {
Any::Float64(value)
impl_primitive_from!(unsigned, u8, u16, u32, u64);
impl_primitive_from!(signed, i8, i16, i32, i64);
impl_primitive_from!(string, String, &str);

impl From<f32> for Any {
fn from(value: f32) -> Self {
Self::Float32(value.into())
}
}

impl From<i64> for Any {
fn from(value: i64) -> Self {
Any::BigInt64(value)
impl From<f64> for Any {
fn from(value: f64) -> Self {
Self::Float64(value.into())
}
}

impl From<bool> for Any {
fn from(value: bool) -> Self {
if value {
Any::True
Self::True
} else {
Any::False
Self::False
}
}
}

impl From<HashMap<String, Any>> for Any {
fn from(value: HashMap<String, Any>) -> Self {
Any::Object(value)
impl FromIterator<Any> for Any {
fn from_iter<I: IntoIterator<Item = Any>>(iter: I) -> Self {
Self::Array(iter.into_iter().collect())
}
}

impl From<Vec<Any>> for Any {
fn from(value: Vec<Any>) -> Self {
Any::Array(value)
impl<'a> FromIterator<&'a Any> for Any {
fn from_iter<I: IntoIterator<Item = &'a Any>>(iter: I) -> Self {
Self::Array(iter.into_iter().cloned().collect())
}
}

impl From<Vec<u8>> for Any {
fn from(value: Vec<u8>) -> Self {
Any::Binary(value)
impl FromIterator<(String, Any)> for Any {
fn from_iter<I: IntoIterator<Item = (String, Any)>>(iter: I) -> Self {
let mut map = HashMap::new();
map.extend(iter);
Self::Object(map)
}
}

impl Any {
fn read_key_value<R: CrdtReader>(reader: &mut R) -> JwstCodecResult<(String, Any)> {
let key = reader.read_var_string()?;
let value = Self::read(reader)?;

Ok((key, value))
impl From<HashMap<String, Any>> for Any {
fn from(value: HashMap<String, Any>) -> Self {
Self::Object(value)
}
}

fn write_key_value<W: CrdtWriter>(writer: &mut W, key: &str, value: &Any) -> JwstCodecResult {
writer.write_var_string(key)?;
value.write(writer)?;

Ok(())
impl From<Vec<u8>> for Any {
fn from(value: Vec<u8>) -> Self {
Self::Binary(value)
}
}

pub(crate) fn read_multiple<R: CrdtReader>(reader: &mut R) -> JwstCodecResult<Vec<Any>> {
let len = reader.read_var_u64()?;
let any = (0..len)
.map(|_| Any::read(reader))
.collect::<Result<Vec<_>, _>>()?;

Ok(any)
impl From<&[u8]> for Any {
fn from(value: &[u8]) -> Self {
Self::Binary(value.into())
}
}

pub(crate) fn write_multiple<W: CrdtWriter>(writer: &mut W, any: &[Any]) -> JwstCodecResult {
writer.write_var_u64(any.len() as u64)?;
for value in any {
value.write(writer)?;
// TODO: impl for Any::Undefined
impl<T: Into<Any>> From<Option<T>> for Any {
fn from(value: Option<T>) -> Self {
if let Some(val) = value {
val.into()
} else {
Any::Null
}

Ok(())
}
}

Expand Down Expand Up @@ -310,4 +340,65 @@ mod tests {
}
}
}

#[test]
fn test_convert_to_any() {
let any: Vec<Any> = vec![
42u8.into(),
42u16.into(),
42u32.into(),
42u64.into(),
114.514f32.into(),
1919.810f64.into(),
(-42i8).into(),
(-42i16).into(),
(-42i32).into(),
(-42i64).into(),
false.into(),
true.into(),
"JWST".to_string().into(),
"OctoBase".into(),
vec![1u8, 9, 1, 9].into(),
(&[8u8, 1, 0][..]).into(),
[Any::True, 42u8.into()].iter().collect(),
];
assert_eq!(
any,
vec![
Any::Integer(42),
Any::Integer(42),
Any::Integer(42),
Any::Integer(42),
Any::Float32(114.514.into()),
Any::Float64(1919.810.into()),
Any::BigInt64(-42),
Any::BigInt64(-42),
Any::BigInt64(-42),
Any::BigInt64(-42),
Any::False,
Any::True,
Any::String("JWST".to_string()),
Any::String("OctoBase".to_string()),
Any::Binary(vec![1, 9, 1, 9]),
Any::Binary(vec![8, 1, 0]),
Any::Array(vec![Any::True, Any::Integer(42)])
]
);

assert_eq!(
vec![("key".to_string(), 10u64.into())]
.into_iter()
.collect::<Any>(),
Any::Object(HashMap::from_iter(vec![(
"key".to_string(),
Any::Integer(10)
)]))
);

let any: Any = 10u64.into();
assert_eq!(
[any].iter().collect::<Any>(),
Any::Array(vec![Any::Integer(10)])
);
}
}
41 changes: 41 additions & 0 deletions libs/jwst-codec/src/doc/codec/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,49 @@ impl Content {

s.split_at(utf_8_offset)
}

pub fn as_array(&self) -> Option<Array> {
if let Self::Type(type_ref) = self {
return Array::try_from(type_ref.clone()).ok();
}
None
}
}

macro_rules! impl_primitive_from {
(any => $($ty:ty),* $(,)?) => {
$(
impl From<$ty> for Content {
fn from(value: $ty) -> Self {
Self::Any(vec![value.into()])
}
}
)*
};
(raw => $($ty:ty: $v:ident),* $(,)?) => {
$(
impl From<$ty> for Content {
fn from(value: $ty) -> Self {
Self::$v(value)
}
}
)*
};
(type_ref => $($ty:ty),* $(,)?) => {
$(
impl From<$ty> for Content {
fn from(type_ref: $ty) -> Self {
Self::Type(type_ref.as_inner().clone())
}
}
)*
}
}

impl_primitive_from! { any => u8, u16, u32, u64, i8, i16, i32, i64, String, &str, f32, f64, bool }
impl_primitive_from! { raw => Vec<u8>: Binary, YTypeRef: Type }
impl_primitive_from! { type_ref => Array, Text }

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

1 comment on commit 4273316

@vercel
Copy link

@vercel vercel bot commented on 4273316 Jun 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.