Skip to content

Commit

Permalink
Make Value API more ergonomic (#80)
Browse files Browse the repository at this point in the history
By using a trait, we can make it more ergonomic to pass other types to
functions that expect a setting value.
  • Loading branch information
CryZe committed Dec 1, 2023
1 parent eeb9ef3 commit 35b9731
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 13 deletions.
16 changes: 16 additions & 0 deletions asr-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ use syn::{spanned::Spanned, Data, DeriveInput, Expr, ExprLit, Lit, Meta};
/// _title: Title,
/// # }
/// ```
///
/// # Tracking changes
///
/// You can track changes to a setting by wrapping the widget type in a `Pair`.
/// It acts like the widget by itself, but also keeps track of the previous
/// value when you call `update` on the struct.
///
/// ```no_run
/// use asr::watcher::Pair;
///
/// #[derive(Gui)]
/// struct Settings {
/// /// Use Game Time
/// use_game_time: Pair<bool>,
/// }
/// ```
#[proc_macro_derive(Gui, attributes(default, heading_level))]
pub fn settings_macro(input: TokenStream) -> TokenStream {
let ast: DeriveInput = syn::parse(input).unwrap();
Expand Down
12 changes: 6 additions & 6 deletions src/runtime/settings/list.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use core::fmt;
use core::{borrow::Borrow, fmt};

use crate::{runtime::sys, Error};

use super::Value;
use super::{AsValue, Value};

/// A list of [`Value`]s that can itself be a [`Value`] and thus be stored in a
/// [`Map`](super::Map).
Expand Down Expand Up @@ -71,22 +71,22 @@ impl List {

/// Pushes a copy of the value to the end of the list.
#[inline]
pub fn push(&self, value: &Value) {
pub fn push(&self, value: impl AsValue) {
// SAFETY: The settings list handle is valid and the value handle is
// valid.
unsafe { sys::settings_list_push(self.0, value.0) }
unsafe { sys::settings_list_push(self.0, value.as_value().borrow().0) }
}

/// Inserts a copy of the value at the given index, pushing all values at
/// and after the index one position further. Returns an error if the index
/// is out of bounds. You may specify an index that is equal to the length
/// of the list to append the value to the end of the list.
#[inline]
pub fn insert(&self, index: u64, value: &Value) -> Result<(), Error> {
pub fn insert(&self, index: u64, value: impl AsValue) -> Result<(), Error> {
// SAFETY: The settings list handle is valid and the value handle is
// valid.
unsafe {
if sys::settings_list_insert(self.0, index, value.0) {
if sys::settings_list_insert(self.0, index, value.as_value().borrow().0) {
Ok(())
} else {
Err(Error {})
Expand Down
12 changes: 7 additions & 5 deletions src/runtime/settings/map.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use core::fmt;
use core::{borrow::Borrow, fmt};

use arrayvec::ArrayString;

use crate::{runtime::sys, Error};

use super::Value;
use super::{AsValue, Value};

/// A map consisting of settings that are configured. Every setting has a string
/// based key and a [`Value`]. There is a global settings map that represents
Expand Down Expand Up @@ -90,13 +90,15 @@ impl Map {
}

/// Inserts a copy of the setting value into the settings map based on the
/// key. If the key already exists, it will be overwritten.
/// key. If the key already exists, the existing value will be overwritten.
#[inline]
pub fn insert(&self, key: &str, value: &Value) {
pub fn insert(&self, key: &str, value: impl AsValue) {
// SAFETY: The settings map handle is valid. We provide a valid pointer
// and length to the key which is guaranteed to be valid UTF-8. The
// setting value handle is also valid.
unsafe { sys::settings_map_insert(self.0, key.as_ptr(), key.len(), value.0) }
unsafe {
sys::settings_map_insert(self.0, key.as_ptr(), key.len(), value.as_value().borrow().0)
}
}

/// Gets a copy of the setting value from the settings map based on the key.
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
//! ```no_run
//! # use asr::settings;
//! let mut map = settings::Map::load();
//! map.insert("key", &true.into());
//! map.insert("key", true);
//! map.store();
//! ```
//!
Expand Down
44 changes: 43 additions & 1 deletion src/runtime/settings/value.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::{fmt, mem::MaybeUninit};
use core::{borrow::Borrow, fmt, mem::MaybeUninit};

use arrayvec::ArrayString;

Expand Down Expand Up @@ -259,6 +259,34 @@ impl Drop for Value {
}
}

/// A trait for types that can be converted into a [`Value`] or allow accessing
/// it as a reference.
pub trait AsValue {
/// The type of the value. It needs to be able to be borrowed as a
/// [`Value`].
type Output: Borrow<Value>;
/// Converts the value into a type that can be borrowed as a [`Value`].
#[allow(clippy::wrong_self_convention)]
fn as_value(self) -> Self::Output;
}

impl<'a> AsValue for &'a Value {
type Output = Self;
fn as_value(self) -> Self::Output {
self
}
}

impl<T> AsValue for T
where
Value: From<T>,
{
type Output = Value;
fn as_value(self) -> Self::Output {
self.into()
}
}

impl From<&Map> for Value {
#[inline]
fn from(value: &Map) -> Self {
Expand All @@ -277,6 +305,20 @@ impl From<&List> for Value {
}
}

impl From<Map> for Value {
#[inline]
fn from(value: Map) -> Self {
(&value).into()
}
}

impl From<List> for Value {
#[inline]
fn from(value: List) -> Self {
(&value).into()
}
}

impl From<bool> for Value {
#[inline]
fn from(value: bool) -> Self {
Expand Down

0 comments on commit 35b9731

Please sign in to comment.