Skip to content

Commit

Permalink
#Rust Add setters for scalar fields
Browse files Browse the repository at this point in the history
  • Loading branch information
candysonya committed Sep 27, 2023
1 parent 70d255a commit 5bdeb2f
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 0 deletions.
131 changes: 131 additions & 0 deletions rust/reflection/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,82 @@ pub unsafe fn get_any_struct_field_string(st: &Struct, field: &Field, schema: &S
)
}

/// Sets any table field with the value of a 64-bit integer. Returns false if the field doesn't point to a valid buffer location or is with non-scalar value.
pub fn set_any_field_integer<'a>(
buf: &'a mut [u8],
field_type: BaseType,
field_loc: usize,
v: i64,
) -> bool {
if !is_scalar(field_type) || buf.len() < field_loc + get_type_size(field_type) {
return false;
}

// Safe because the index was verified above.
unsafe { set_any_value_integer(field_type, &mut buf[field_loc..], v) }
}

/// Sets any table field with the value of a 64-bit floating point. Returns false if the field doesn't point to a valid buffer location or is with non-scalar value.
pub fn set_any_field_float<'a>(
buf: &'a mut [u8],
field_type: BaseType,
field_loc: usize,
v: f64,
) -> bool {
if !is_scalar(field_type) || buf.len() < field_loc + get_type_size(field_type) {
return false;
}

// Safe because the index was verified above.
unsafe {
set_any_value_float(field_type, &mut buf[field_loc..], v);
}
true
}

/// Sets any table field with the value of a string. Returns false if the field doesn't point to a valid buffer location or is with non-scalar value.
pub fn set_any_field_string<'a>(
buf: &'a mut [u8],
field_type: BaseType,
field_loc: usize,
v: &str,
) -> bool {
if !is_scalar(field_type) || buf.len() < field_loc + get_type_size(field_type) {
return false;
}

// Safe because the index was verified above.
unsafe {
set_any_value_string(field_type, &mut buf[field_loc..], v);
}
true
}

/// Sets any scalar field given its exact type. Returns false if the field doesn't point to a valid buffer location or is with non-scalar value.
pub fn set_field<'a, T: EndianScalar>(
buf: &'a mut [u8],
field_type: BaseType,
field_loc: Option<usize>,
v: T,
) -> bool {
if !is_scalar(field_type) || core::mem::size_of::<T>() != get_type_size(field_type) {
return false;
}

if field_loc.is_none() {
return false;
}

let field_loc = field_loc.unwrap();
if buf.len() < field_loc + get_type_size(field_type) {
return false;
}

// Safe because the index was verified above.
unsafe { emplace_scalar::<T>(&mut buf[field_loc..], v) };
true
}

/// Returns the size of a scalar type in the `BaseType` enum. In the case of structs, returns the size of their offset (`UOffsetT`) in the buffer.
fn get_type_size(base_type: BaseType) -> usize {
match base_type {
Expand Down Expand Up @@ -318,3 +394,58 @@ unsafe fn get_any_value_string(
_ => get_any_value_integer(base_type, buf, loc).to_string(),
}
}

/// Sets any scalar value with a 64-bit integer.
///
/// # Safety
///
/// Caller must ensure `buf.len() >= loc + size_of::<T>()`.
pub unsafe fn set_any_value_integer(base_type: BaseType, buf: &mut [u8], v: i64) -> bool {
match base_type {
BaseType::UType | BaseType::UByte => emplace_scalar::<u8>(buf, (v as u8).into()),
BaseType::Bool => emplace_scalar::<bool>(buf, v != 0),
BaseType::Byte => emplace_scalar::<i8>(buf, (v as i8).into()),
BaseType::Short => emplace_scalar::<i16>(buf, (v as i16).into()),
BaseType::UShort => emplace_scalar::<u16>(buf, (v as u16).into()),
BaseType::Int => emplace_scalar::<i32>(buf, (v as i32).into()),
BaseType::UInt => emplace_scalar::<u32>(buf, (v as u32).into()),
BaseType::Long => emplace_scalar::<i64>(buf, v),
BaseType::ULong => emplace_scalar::<u64>(buf, v as u64),
BaseType::Float => emplace_scalar::<f32>(buf, (v as f32).into()),
BaseType::Double => emplace_scalar::<f64>(buf, v as f64),
_ => return false,
}
true
}

/// Sets any scalar value with a 64-bit floating point.
///
/// # Safety
///
/// Caller must ensure `buf.len() >= loc + size_of::<T>()`.
pub unsafe fn set_any_value_float(base_type: BaseType, buf: &mut [u8], v: f64) -> bool {
match base_type {
BaseType::Float => emplace_scalar::<f32>(buf, (v as f32).into()),
BaseType::Double => emplace_scalar::<f64>(buf, v),
_ => return set_any_value_integer(base_type, buf, (v as i64).into()),
}
true
}

/// Sets any scalar value with a string.
///
/// # Safety
///
/// Caller must ensure `buf.len() >= loc + size_of::<T>()`.
pub unsafe fn set_any_value_string(base_type: BaseType, buf: &mut [u8], v: &str) -> bool {
match base_type {
BaseType::Float | BaseType::Double => {
set_any_value_float(base_type, buf, v.parse::<f64>().unwrap_or_default())
}
_ => set_any_value_integer(base_type, buf, v.parse::<i64>().unwrap_or_default()),
}
}

fn is_scalar(base_type: BaseType) -> bool {
return base_type <= BaseType::Double;
}
35 changes: 35 additions & 0 deletions tests/rust_reflection_test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,41 @@ fn test_schema() {
},
5.0
);

// Sets fields generically:
let hp_field_loc = get_field_loc(&root_table, &hp_field);
assert!(hp_field_loc.is_some());
assert_eq!(
set_any_field_integer(
mutable_buf,
hp_field.type_().base_type(),
hp_field_loc.unwrap(),
300
),
true
);
let root_table = unsafe { get_any_root(&mutable_buf) };
let hp_int64 = unsafe { get_any_field_integer(&root_table, &hp_field) };
assert_eq!(hp_int64, 300);

assert_eq!(
set_any_field_float(flatbuf, hp_field.type_().base_type(), hp_field_loc.unwrap(), 300.5),
true
);
let root_table = unsafe { get_any_root(&mutable_buf) };
let hp_int64 = unsafe { get_any_field_integer(&root_table, &hp_field) };
assert_eq!(hp_int64, 300);

assert_eq!(
set_any_field_string(flatbuf, hp_field.type_().base_type(), hp_field_loc.unwrap(), "300"),
true
);
let root_table = unsafe { get_any_root(&mutable_buf) };
let hp_int64 = unsafe { get_any_field_integer(&root_table, &hp_field) };
assert_eq!(hp_int64, 300);

// Resets it, for further tests.
assert_eq!(set_field::<u16>(flatbuf, hp_field.type_().base_type(), hp_field_loc, 80), true);
}

// Builds up a serialized buffer algorithmically.
Expand Down

0 comments on commit 5bdeb2f

Please sign in to comment.