Skip to content

Commit

Permalink
support polymorphism
Browse files Browse the repository at this point in the history
  • Loading branch information
theweipeng committed Aug 7, 2024
1 parent 0e18130 commit c14ec8f
Show file tree
Hide file tree
Showing 26 changed files with 427 additions and 160 deletions.
11 changes: 11 additions & 0 deletions rust/fury-core/src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,15 @@ impl<'bf> Reader<'bf> {
self.move_next(len);
result
}

pub fn reset_cursor_to_here(&self) -> impl FnOnce(&mut Self) {
let raw_cursor = self.cursor;
move |this: &mut Self| {
this.cursor = raw_cursor;
}
}

pub fn aligned<T>(&self) -> bool {
unsafe { (self.bf.as_ptr().add(self.cursor) as usize) % align_of::<T>() == 0 }
}
}
7 changes: 5 additions & 2 deletions rust/fury-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.

use super::types::{FieldType, Language};
use super::types::Language;

#[derive(thiserror::Error, Debug)]
pub enum Error {
Expand All @@ -32,7 +32,7 @@ pub enum Error {
BadRefFlag,

#[error("Bad FieldType; expected: {expected:?}, actual: {actial:?}")]
FieldType { expected: FieldType, actial: i16 },
FieldType { expected: i16, actial: i16 },

#[error("Bad timestamp; out-of-range number of milliseconds")]
NaiveDateTime,
Expand Down Expand Up @@ -75,4 +75,7 @@ pub enum Error {

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

#[error("Unregistered type when serializing or deserializing object of Any type: {value:?}")]
UnregisteredType { value: u32 },
}
14 changes: 13 additions & 1 deletion rust/fury-core/src/fury.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@

use crate::buffer::{Reader, Writer};
use crate::error::Error;
use crate::resolver::class_resolver::{ClassInfo, ClassResolver};
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
use crate::serializer::Serializer;
use crate::serializer::{Serializer, StructSerializer};
use crate::types::{config_flags, Language, Mode, SIZE_OF_REF_AND_TYPE};

pub struct Fury {
mode: Mode,
class_resolver: ClassResolver,
}

impl Default for Fury {
fn default() -> Self {
Fury {
mode: Mode::SchemaConsistent,
class_resolver: ClassResolver::default(),
}
}
}
Expand Down Expand Up @@ -82,4 +85,13 @@ impl Fury {
}
writer.dump()
}

pub fn get_class_resolver(&self) -> &ClassResolver {
&self.class_resolver
}

pub fn register<T: 'static + StructSerializer>(&mut self, id: u32) {
let class_info = ClassInfo::new::<T>(self, id);
self.class_resolver.register::<T>(class_info, id);
}
}
21 changes: 13 additions & 8 deletions rust/fury-core/src/meta/type_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,17 @@ use super::meta_string::MetaStringEncoder;
use crate::buffer::{Reader, Writer};
use crate::error::Error;
use crate::meta::{Encoding, MetaStringDecoder};
use crate::types::FieldType;

//todo backward/forward compatibility
#[allow(dead_code)]
pub struct FieldInfo {
field_name: String,
field_type: FieldType,
field_id: i16,
}

impl FieldInfo {
pub fn new(field_name: &str, field_type: FieldType) -> FieldInfo {
pub fn new(field_name: &str, field_type: i16) -> FieldInfo {
FieldInfo {
field_name: field_name.to_string(),
field_type,
field_id: field_type,
}
}

Expand Down Expand Up @@ -60,7 +57,7 @@ impl FieldInfo {
.unwrap();
FieldInfo {
field_name,
field_type: FieldType::try_from(type_id).unwrap(),
field_id: type_id,
}
}

Expand All @@ -80,7 +77,7 @@ impl FieldInfo {
header |= (size << 5) as u8;
writer.u8(header);
}
writer.i16(self.field_type as i16);
writer.i16(self.field_id);
writer.bytes(encoded);
Ok(writer.dump())
}
Expand All @@ -99,6 +96,10 @@ impl TypeMetaLayer {
}
}

pub fn get_type_id(&self) -> u32 {
self.type_id
}

pub fn get_field_info(&self) -> &Vec<FieldInfo> {
&self.field_info
}
Expand Down Expand Up @@ -133,6 +134,10 @@ impl TypeMeta {
self.layers.first().unwrap().get_field_info()
}

pub fn get_type_id(&self) -> u32 {
self.layers.first().unwrap().get_type_id()
}

pub fn from_fields(type_id: u32, field_info: Vec<FieldInfo>) -> TypeMeta {
TypeMeta {
hash: 0,
Expand Down
116 changes: 116 additions & 0 deletions rust/fury-core/src/resolver/class_resolver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// 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 super::context::{ReadContext, WriteContext};
use crate::error::Error;
use crate::fury::Fury;
use crate::serializer::StructSerializer;
use std::any::TypeId;
use std::{any::Any, collections::HashMap};

pub struct Harness {
serializer: fn(&dyn Any, &mut WriteContext),
deserializer: fn(&mut ReadContext) -> Result<Box<dyn Any>, Error>,
}

impl Harness {
pub fn new(
serializer: fn(&dyn Any, &mut WriteContext),
deserializer: fn(&mut ReadContext) -> Result<Box<dyn Any>, Error>,
) -> Harness {
Harness {
serializer,
deserializer,
}
}

pub fn get_serializer(&self) -> fn(&dyn Any, &mut WriteContext) {
self.serializer
}

pub fn get_deserializer(&self) -> fn(&mut ReadContext) -> Result<Box<dyn Any>, Error> {
self.deserializer
}
}

pub struct ClassInfo {
type_def: Vec<u8>,
type_id: u32,
}

impl ClassInfo {
pub fn new<T: StructSerializer>(fury: &Fury, type_id: u32) -> ClassInfo {
ClassInfo {
type_def: T::type_def(fury),
type_id,
}
}

pub fn get_type_id(&self) -> u32 {
self.type_id
}

pub fn get_type_def(&self) -> &Vec<u8> {
&self.type_def
}
}

#[derive(Default)]
pub struct ClassResolver {
serialize_map: HashMap<u32, Harness>,
type_id_map: HashMap<TypeId, u32>,
class_info_map: HashMap<TypeId, ClassInfo>,
}

impl ClassResolver {
pub fn get_class_info(&self, type_id: TypeId) -> &ClassInfo {
self.class_info_map.get(&type_id).unwrap()
}

pub fn register<T: StructSerializer>(&mut self, class_info: ClassInfo, id: u32) {
fn serializer<T2: 'static + StructSerializer>(this: &dyn Any, context: &mut WriteContext) {
let this = this.downcast_ref::<T2>();
match this {
Some(v) => {
T2::serialize(v, context);
}
None => todo!(),
}
}

fn deserializer<T2: 'static + StructSerializer>(
context: &mut ReadContext,
) -> Result<Box<dyn Any>, Error> {
match T2::deserialize(context) {
Ok(v) => Ok(Box::new(v)),
Err(e) => Err(e),
}
}
self.type_id_map.insert(TypeId::of::<T>(), id);
self.serialize_map
.insert(id, Harness::new(serializer::<T>, deserializer::<T>));
self.class_info_map.insert(TypeId::of::<T>(), class_info);
}

pub fn get_harness_by_type(&self, type_id: TypeId) -> Option<&Harness> {
self.get_harness(*self.type_id_map.get(&type_id).unwrap())
}

pub fn get_harness(&self, id: u32) -> Option<&Harness> {
self.serialize_map.get(&id)
}
}
4 changes: 2 additions & 2 deletions rust/fury-core/src/resolver/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ impl<'se> WriteContext<'se> {
}
}

pub fn push_meta(&mut self, type_id: TypeId, type_def: &'static [u8]) -> usize {
self.meta_resolver.push(type_id, type_def)
pub fn push_meta(&mut self, type_id: TypeId) -> usize {
self.meta_resolver.push(type_id, self.fury)
}

pub fn write_meta(&mut self, offset: usize) {
Expand Down
11 changes: 8 additions & 3 deletions rust/fury-core/src/resolver/meta_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

use crate::buffer::{Reader, Writer};
use crate::error::Error;
use crate::fury::Fury;
use crate::meta::TypeMeta;
use std::any::TypeId;
use std::collections::HashMap;
Expand Down Expand Up @@ -44,17 +45,21 @@ impl MetaReaderResolver {

#[derive(Default)]
pub struct MetaWriterResolver<'a> {
type_defs: Vec<&'a [u8]>,
type_defs: Vec<&'a Vec<u8>>,
type_id_index_map: HashMap<TypeId, usize>,
}

#[allow(dead_code)]
impl<'a> MetaWriterResolver<'a> {
pub fn push<'b: 'a>(&mut self, type_id: TypeId, type_meta_bytes: &'b [u8]) -> usize {
pub fn push<'b: 'a>(&mut self, type_id: TypeId, fury: &'a Fury) -> usize {
match self.type_id_index_map.get(&type_id) {
None => {
let index = self.type_defs.len();
self.type_defs.push(type_meta_bytes);
self.type_defs.push(
fury.get_class_resolver()
.get_class_info(type_id)
.get_type_def(),
);
self.type_id_index_map.insert(type_id, index);
index
}
Expand Down
1 change: 1 addition & 0 deletions rust/fury-core/src/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
// specific language governing permissions and limitations
// under the License.

pub mod class_resolver;
pub mod context;
pub mod meta_resolver;
87 changes: 87 additions & 0 deletions rust/fury-core/src/serializer/any.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// 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::fury::Fury;
use crate::resolver::context::{ReadContext, WriteContext};
use crate::serializer::Serializer;
use crate::types::{FieldType, Mode, RefFlag};
use std::any::Any;

impl Serializer for Box<dyn Any> {
fn reserved_space() -> usize {
0
}

fn write(&self, _context: &mut WriteContext) {
panic!("unreachable")
}

fn read(_context: &mut ReadContext) -> Result<Self, Error> {
panic!("unreachable")
}

fn ty(_fury: &Fury) -> i16 {
FieldType::FuryTypeTag.into()
}

fn serialize(&self, context: &mut WriteContext) {
context
.get_fury()
.get_class_resolver()
.get_harness_by_type(self.as_ref().type_id())
.unwrap()
.get_serializer()(self.as_ref(), context);
}

fn deserialize(context: &mut ReadContext) -> Result<Self, Error> {
let reset_cursor = context.reader.reset_cursor_to_here();
// ref flag
let ref_flag = context.reader.i8();

if ref_flag == (RefFlag::NotNullValue as i8) || ref_flag == (RefFlag::RefValue as i8) {
if context.get_fury().get_mode().eq(&Mode::Compatible) {
let meta_index = context.reader.i16();
let type_id = context.meta_resolver.get(meta_index as usize).get_type_id();
reset_cursor(&mut context.reader);
context
.get_fury()
.get_class_resolver()
.get_harness(type_id)
.unwrap()
.get_deserializer()(context)
} else {
let type_id = context.reader.i16();
reset_cursor(&mut context.reader);
context
.get_fury()
.get_class_resolver()
.get_harness(type_id as u32)
.unwrap()
.get_deserializer()(context)
}
} else if ref_flag == (RefFlag::Null as i8) {
Err(Error::Null)
} else if ref_flag == (RefFlag::Ref as i8) {
reset_cursor(&mut context.reader);
Err(Error::Ref)
} else {
reset_cursor(&mut context.reader);
Err(Error::BadRefFlag)
}
}
}
Loading

0 comments on commit c14ec8f

Please sign in to comment.