Skip to content

Commit

Permalink
feat(Rust): Refine Code Structure & Prepare for Future Compatibility …
Browse files Browse the repository at this point in the history
…Features (#1787)
  • Loading branch information
theweipeng authored Aug 2, 2024
1 parent 7052bee commit fb34adf
Show file tree
Hide file tree
Showing 46 changed files with 1,324 additions and 976 deletions.
1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

[workspace]
members = [
"fury-core",
"fury",
"fury-derive",
"tests"
Expand Down
41 changes: 41 additions & 0 deletions rust/fury-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

[package]
name = "fury-core"
version.workspace = true
edition.workspace = true
rust-version.workspace = true

[dependencies]
proc-macro2 = { default-features = false, version = "1.0" }
syn = { default-features = false, version = "2.0", features = ["full", "fold"] }
quote = { default-features = false, version = "1.0" }
lazy_static = { version = "1.4" }
byteorder = { version = "1.4" }
chrono = "0.4"
thiserror = { default-features = false, version = "1.0" }


[[bench]]
name = "simd_bench"
harness = false


[dev-dependencies]
criterion = "0.5.1"
rand = "0.8.5"
File renamed without changes.
File renamed without changes.
25 changes: 23 additions & 2 deletions rust/fury/src/error.rs → rust/fury-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,29 @@ pub enum Error {
TagType(u8),

#[error("Only Xlang supported; receive: {language:?}")]
UnsupportLanguage { language: Language },
UnsupportedLanguage { language: Language },

#[error("Unsupported Language Code; receive: {code:?}")]
UnsupportLanguageCode { code: u8 },
UnsupportedLanguageCode { code: u8 },

#[error("encoded_data cannot be empty")]
EncodedDataEmpty,

#[error("Long meta string than 32767 is not allowed")]
LengthExceed,

#[error("Non-ASCII characters in meta string are not allowed")]
OnlyAllowASCII,

#[error("Unsupported character for LOWER_SPECIAL encoding: {ch:?}")]
UnsupportedLowerSpecialCharacter { ch: char },

#[error("Unsupported character for LOWER_UPPER_DIGIT_SPECIAL encoding: {ch:?}")]
UnsupportedLowerUpperDigitSpecialCharacter { ch: char },

#[error("Invalid character value for LOWER_SPECIAL decoding: {value:?}")]
InvalidLowerSpecialValue { value: u8 },

#[error("Invalid character value for LOWER_UPPER_DIGIT_SPECIAL decoding: {value:?}")]
InvalidLowerUpperDigitSpecialValue { value: u8 },
}
60 changes: 60 additions & 0 deletions rust/fury-core/src/fury.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::buffer::{Reader, Writer};
use crate::error::Error;
use crate::read_state::ReadState;
use crate::serializer::Serializer;
use crate::types::Mode;
use crate::write_state::WriteState;

pub struct Fury {
mode: Mode,
}

impl Default for Fury {
fn default() -> Self {
Fury {
mode: Mode::Compatible,
}
}
}

impl Fury {
pub fn mode(&mut self, mode: Mode) {
self.mode = mode;
}

pub fn get_mode(&self) -> &Mode {
&self.mode
}

pub fn deserialize<T: Serializer>(&self, bf: &[u8]) -> Result<T, Error> {
let reader = Reader::new(bf);
let mut deserializer = ReadState::new(self, reader);
deserializer.head()?;
<T as Serializer>::deserialize(&mut deserializer)
}

pub fn serialize<T: Serializer>(&self, record: &T) -> Vec<u8> {
let mut writer = Writer::default();
let mut serializer = WriteState::new(self, &mut writer);
serializer.head::<T>();
<T as Serializer>::serialize(record, &mut serializer);
writer.dump()
}
}
41 changes: 41 additions & 0 deletions rust/fury-core/src/internal/bool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::error::Error;
use crate::read_state::ReadState;
use crate::serializer::Serializer;
use crate::types::FieldType;
use crate::write_state::WriteState;
use std::mem;

impl Serializer for bool {
fn reserved_space() -> usize {
mem::size_of::<i32>()
}

fn write(&self, serializer: &mut WriteState) {
serializer.writer.u8(if *self { 1 } else { 0 });
}

fn read(deserializer: &mut ReadState) -> Result<Self, Error> {
Ok(deserializer.reader.u8() == 1)
}

fn ty() -> FieldType {
FieldType::BOOL
}
}
80 changes: 80 additions & 0 deletions rust/fury-core/src/internal/datetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::error::Error;
use crate::read_state::ReadState;
use crate::serializer::Serializer;
use crate::types::{FieldType, FuryGeneralList};
use crate::write_state::WriteState;
use chrono::{DateTime, Days, NaiveDate, NaiveDateTime};
use std::mem;

impl Serializer for NaiveDateTime {
fn read(deserializer: &mut ReadState) -> Result<Self, Error> {
let timestamp = deserializer.reader.u64();
let ret = DateTime::from_timestamp_millis(timestamp as i64).map(|dt| dt.naive_utc());
match ret {
Some(r) => Ok(r),
None => Err(Error::NaiveDateTime),
}
}

fn write(&self, serializer: &mut WriteState) {
serializer
.writer
.u64(self.and_utc().timestamp_millis() as u64);
}

fn reserved_space() -> usize {
mem::size_of::<u64>()
}

fn ty() -> FieldType {
FieldType::TIMESTAMP
}
}

impl FuryGeneralList for NaiveDateTime {}

lazy_static::lazy_static!(
static ref EPOCH: NaiveDate = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
);

impl Serializer for NaiveDate {
fn write(&self, serializer: &mut WriteState) {
let days_since_epoch = self.signed_duration_since(*EPOCH).num_days();
serializer.writer.u64(days_since_epoch as u64);
}

fn reserved_space() -> usize {
mem::size_of::<u64>()
}

fn read(serializer: &mut ReadState) -> Result<Self, Error> {
let days = serializer.reader.u64();
match EPOCH.checked_add_days(Days::new(days)) {
Some(value) => Ok(value),
None => Err(Error::NaiveDate),
}
}

fn ty() -> FieldType {
FieldType::DATE
}
}

impl FuryGeneralList for NaiveDate {}
60 changes: 60 additions & 0 deletions rust/fury-core/src/internal/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::error::Error;
use crate::read_state::ReadState;
use crate::serializer::Serializer;
use crate::types::{FieldType, FuryGeneralList, SIZE_OF_REF_AND_TYPE};
use crate::write_state::WriteState;
use std::mem;

impl<T> Serializer for Vec<T>
where
T: Serializer + FuryGeneralList,
{
fn write(&self, serializer: &mut WriteState) {
serializer.writer.var_int32(self.len() as i32);
serializer
.writer
.reserve((<Self as Serializer>::reserved_space() + SIZE_OF_REF_AND_TYPE) * self.len());
for item in self.iter() {
item.serialize(serializer);
}
}

fn read(deserializer: &mut ReadState) -> Result<Self, Error> {
// length
let len = deserializer.reader.var_int32();
// value
let mut result = Vec::new();
for _ in 0..len {
result.push(T::deserialize(deserializer)?);
}
Ok(result)
}

fn reserved_space() -> usize {
// size of the vec
mem::size_of::<u32>()
}

fn ty() -> FieldType {
FieldType::ARRAY
}
}

impl<T> FuryGeneralList for Vec<T> where T: Serializer {}
66 changes: 66 additions & 0 deletions rust/fury-core/src/internal/map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::error::Error;
use crate::read_state::ReadState;
use crate::serializer::Serializer;
use crate::types::{FieldType, FuryGeneralList, SIZE_OF_REF_AND_TYPE};
use crate::write_state::WriteState;
use std::collections::HashMap;
use std::mem;

impl<T1: Serializer + Eq + std::hash::Hash, T2: Serializer> Serializer for HashMap<T1, T2> {
fn write(&self, serializer: &mut WriteState) {
// length
serializer.writer.var_int32(self.len() as i32);

let reserved_space = (<T1 as Serializer>::reserved_space() + SIZE_OF_REF_AND_TYPE)
* self.len()
+ (<T2 as Serializer>::reserved_space() + SIZE_OF_REF_AND_TYPE) * self.len();
serializer.writer.reserve(reserved_space);

// key-value
for i in self.iter() {
i.0.serialize(serializer);
i.1.serialize(serializer);
}
}

fn read(deserializer: &mut ReadState) -> Result<Self, Error> {
// length
let len = deserializer.reader.var_int32();
let mut result = HashMap::new();
// key-value
for _ in 0..len {
result.insert(
<T1 as Serializer>::deserialize(deserializer)?,
<T2 as Serializer>::deserialize(deserializer)?,
);
}
Ok(result)
}

fn reserved_space() -> usize {
mem::size_of::<i32>()
}

fn ty() -> FieldType {
FieldType::MAP
}
}

impl<T1: Serializer + Eq + std::hash::Hash, T2: Serializer> FuryGeneralList for HashMap<T1, T2> {}
Loading

0 comments on commit fb34adf

Please sign in to comment.