Skip to content

Commit

Permalink
Add function for querying the type of a value (#79)
Browse files Browse the repository at this point in the history
This adds a function to the runtime that allows querying the type of a
setting value. Especially if you don't know the type before hand, such
as when debug printing or deserializing, this can be useful.
Additionally this could be useful for lossy conversions.
  • Loading branch information
CryZe committed Nov 14, 2023
1 parent d0fbc56 commit eeb9ef3
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ extern crate alloc;
mod primitives;
mod runtime;

pub mod deep_pointer;
pub mod emulator;
#[macro_use]
pub mod future;
Expand All @@ -143,7 +144,6 @@ pub mod time_util;
#[cfg(all(feature = "wasi-no-std", target_os = "wasi"))]
mod wasi_no_std;
pub mod watcher;
pub mod deep_pointer;

pub use self::{primitives::*, runtime::*};
pub use arrayvec;
Expand Down
96 changes: 75 additions & 21 deletions src/runtime/settings/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ use crate::{runtime::sys, Error};

use super::{List, Map};

/// The type of a setting [`Value`].
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ValueType {
/// A [`Map`] of key-value pairs of [`Value`]s.
Map = 1,
/// A [`List`] of [`Value`]s.
List,
/// A boolean.
Bool,
/// A 64-bit signed integer.
I64,
/// A 64-bit floating point number.
F64,
/// A string.
String,
/// The type is not known. This is likely the case if the auto splitter is
/// running on a newer runtime that supports more types.
Unknown,
}

/// A value of a setting. This can be a value of any type that a setting can
/// hold. Currently this is either a [`Map`], a [`List`], a [`bool`], an
/// [`i64`], an [`f64`], or a string.
Expand All @@ -15,32 +36,48 @@ pub struct Value(pub(super) sys::SettingValue);
impl fmt::Debug for Value {
#[allow(clippy::collapsible_match)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// TODO: Do a type check first.
if let Some(v) = self.get_map() {
fmt::Debug::fmt(&v, f)
} else if let Some(v) = self.get_list() {
fmt::Debug::fmt(&v, f)
} else if let Some(v) = self.get_bool() {
fmt::Debug::fmt(&v, f)
} else if let Some(v) = self.get_i64() {
fmt::Debug::fmt(&v, f)
} else if let Some(v) = self.get_f64() {
fmt::Debug::fmt(&v, f)
} else {
if let Some(v) = self.get_array_string::<128>() {
if let Ok(v) = v {
match self.get_type() {
ValueType::Map => {
if let Some(v) = self.get_map() {
return fmt::Debug::fmt(&v, f);
}
#[cfg(not(feature = "alloc"))]
return f.write_str("<Long string>");
}
#[cfg(feature = "alloc")]
if let Some(v) = self.get_string() {
return fmt::Debug::fmt(&v, f);
ValueType::List => {
if let Some(v) = self.get_list() {
return fmt::Debug::fmt(&v, f);
}
}

f.write_str("<Unknown>")
ValueType::Bool => {
if let Some(v) = self.get_bool() {
return fmt::Debug::fmt(&v, f);
}
}
ValueType::I64 => {
if let Some(v) = self.get_i64() {
return fmt::Debug::fmt(&v, f);
}
}
ValueType::F64 => {
if let Some(v) = self.get_f64() {
return fmt::Debug::fmt(&v, f);
}
}
ValueType::String => {
if let Some(v) = self.get_array_string::<128>() {
if let Ok(v) = v {
return fmt::Debug::fmt(&v, f);
}
#[cfg(not(feature = "alloc"))]
return f.write_str("<Long string>");
}
#[cfg(feature = "alloc")]
if let Some(v) = self.get_string() {
return fmt::Debug::fmt(&v, f);
}
}
_ => {}
}
f.write_str("<Unknown>")
}
}

Expand All @@ -61,6 +98,23 @@ impl Value {
value.into()
}

/// Returns the type of the value.
#[inline]
pub fn get_type(&self) -> ValueType {
// SAFETY: The handle is valid, so we can safely call this function.
unsafe {
match sys::setting_value_get_type(self.0) {
sys::SettingValueType::MAP => ValueType::Map,
sys::SettingValueType::LIST => ValueType::List,
sys::SettingValueType::BOOL => ValueType::Bool,
sys::SettingValueType::I64 => ValueType::I64,
sys::SettingValueType::F64 => ValueType::F64,
sys::SettingValueType::STRING => ValueType::String,
_ => ValueType::Unknown,
}
}
}

/// Returns the value as a [`Map`] if it is a map. The map is a copy, so any
/// changes to it are not reflected in the setting value.
#[inline]
Expand Down
21 changes: 21 additions & 0 deletions src/runtime/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,25 @@ pub struct SettingsList(NonZeroU64);
#[repr(transparent)]
pub struct SettingValue(NonZeroU64);

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct SettingValueType(u32);

impl SettingValueType {
/// The setting value is a settings map.
pub const MAP: Self = Self(1);
/// The setting value is a settings list.
pub const LIST: Self = Self(2);
/// The setting value is a boolean.
pub const BOOL: Self = Self(3);
/// The setting value is a 64-bit signed integer.
pub const I64: Self = Self(4);
/// The setting value is a 64-bit floating point number.
pub const F64: Self = Self(5);
/// The setting value is a string.
pub const STRING: Self = Self(6);
}

extern "C" {
/// Gets the state that the timer currently is in.
pub fn timer_get_state() -> TimerState;
Expand Down Expand Up @@ -347,6 +366,8 @@ extern "C" {
/// setting value. You own the new setting value and are responsible for
/// freeing it.
pub fn setting_value_copy(value: SettingValue) -> SettingValue;
/// Gets the type of a setting value.
pub fn setting_value_get_type(value: SettingValue) -> SettingValueType;
/// Gets the value of a setting value as a settings map by storing it into
/// the pointer provided. Returns `false` if the setting value is not a
/// settings map. No value is stored into the pointer in that case. No
Expand Down

0 comments on commit eeb9ef3

Please sign in to comment.