Skip to content

Commit

Permalink
Replace Context by App (#315)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicolas-Ferre authored Jul 20, 2024
1 parent 8102728 commit 60c4c94
Show file tree
Hide file tree
Showing 88 changed files with 1,098 additions and 1,174 deletions.
95 changes: 36 additions & 59 deletions crates/modor/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ impl App {
/// [`Node::update`] method is called for each registered root node.
///
/// Root nodes are updated in the order in which they are created.
///
/// # Panics
///
/// This will panic if any root node is already borrowed.
pub fn update(&mut self) {
debug!("Run update app...");
for root_index in 0..self.roots.len() {
Expand All @@ -61,22 +65,40 @@ impl App {
.take()
.expect("internal error: root node already borrowed");
let update_fn = root.update_fn;
update_fn(&mut *value, &mut self.ctx());
update_fn(&mut *value, self);
self.roots[root_index].value = Some(value);
}
debug!("App updated");
}

/// Returns an update context.
/// Returns a handle to a root node.
///
/// This method is generally used for testing purpose.
pub fn ctx(&mut self) -> Context<'_> {
Context { app: self }
/// The root node is created using [`RootNode::on_create`] if it doesn't exist.
pub fn handle<T>(&mut self) -> RootNodeHandle<T>
where
T: RootNode,
{
RootNodeHandle {
index: self.root_index_or_create::<T>(),
phantom: PhantomData,
}
}

/// Creates the root node of type `T` using [`RootNode::on_create`] if it doesn't exist.
pub fn create<T>(&mut self)
where
T: RootNode,
{
self.handle::<T>();
}

/// Returns a mutable reference to a root node.
///
/// The root node is created using [`RootNode::on_create`] if it doesn't exist.
///
/// # Panics
///
/// This will panic if root node `T` is already borrowed.
pub fn get_mut<T>(&mut self) -> &mut T
where
T: RootNode,
Expand All @@ -102,7 +124,7 @@ impl App {
T: RootNode,
{
debug!("Create root node `{}`...", any::type_name::<T>());
let root = RootNodeData::new(T::on_create(&mut self.ctx()));
let root = RootNodeData::new(T::on_create(self));
debug!("Root node `{}` created", any::type_name::<T>());
let index = self.roots.len();
self.root_indexes.insert(type_id, index);
Expand All @@ -123,51 +145,6 @@ impl App {
}
}

// If `App` was directly accessible during update, it would be possible to run `App::update`.
// As this is not wanted, `App` is wrapped in `Context` to limit the allowed operations.
/// The context accessible during node update.
#[derive(Debug)]
pub struct Context<'a> {
app: &'a mut App,
}

impl Context<'_> {
/// Returns a handle to a root node.
///
/// The root node is created using [`RootNode::on_create`] if it doesn't exist.
pub fn handle<T>(&mut self) -> RootNodeHandle<T>
where
T: RootNode,
{
RootNodeHandle {
index: self.app.root_index_or_create::<T>(),
phantom: PhantomData,
}
}

/// Returns a mutable reference to a root node.
///
/// The root node is created using [`RootNode::on_create`] if it doesn't exist.
///
/// # Panics
///
/// This will panic if root node `T` is currently updated.
pub fn get_mut<T>(&mut self) -> &mut T
where
T: RootNode,
{
self.handle::<T>().get_mut(self)
}

/// Creates the root node of type `T` using [`RootNode::on_create`] if it doesn't exist.
pub fn create<T>(&mut self)
where
T: RootNode,
{
self.handle::<T>();
}
}

/// A handle to access a [`RootNode`].
#[derive(Derivative)]
#[derivative(
Expand All @@ -190,25 +167,25 @@ where
T: RootNode,
{
/// Returns an immutable reference to the root node.
pub fn get<'a>(self, ctx: &'a Context<'_>) -> &'a T {
ctx.app.roots[self.index]
pub fn get(self, app: &App) -> &T {
app.roots[self.index]
.value
.as_ref()
.unwrap_or_else(|| panic!("root node `{}` already borrowed", any::type_name::<T>()))
.downcast_ref::<T>()
.expect("internal error: misconfigured root node")
}

/// Returns an immutable reference to the root node.
pub fn get_mut<'a>(self, ctx: &'a mut Context<'_>) -> &'a mut T {
ctx.app.root_mut(self.index)
/// Returns a mutable reference to the root node.
pub fn get_mut(self, app: &mut App) -> &mut T {
app.root_mut(self.index)
}
}

#[derive(Debug)]
struct RootNodeData {
value: Option<Box<dyn Any>>,
update_fn: fn(&mut dyn Any, &mut Context<'_>),
update_fn: fn(&mut dyn Any, &mut App),
}

impl RootNodeData {
Expand All @@ -222,15 +199,15 @@ impl RootNodeData {
}
}

fn update_root<T>(value: &mut dyn Any, ctx: &mut Context<'_>)
fn update_root<T>(value: &mut dyn Any, app: &mut App)
where
T: RootNode,
{
Node::update(
value
.downcast_mut::<T>()
.expect("internal error: misconfigured root node"),
ctx,
app,
);
}
}
42 changes: 21 additions & 21 deletions crates/modor/src/globals.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(clippy::non_canonical_partial_ord_impl)] // warnings caused by Derivative

use crate::{Context, Node, RootNode, RootNodeHandle, Visit};
use crate::{App, Node, RootNode, RootNodeHandle, Visit};
use derivative::Derivative;
use log::error;
use std::iter::Flatten;
Expand All @@ -17,9 +17,9 @@ use std::sync::{Arc, Mutex};
/// ```
/// # use modor::*;
/// #
/// fn create_glob(ctx: &mut Context<'_>) -> Glob<&'static str> {
/// let glob = Glob::new(ctx, "shared value");
/// assert_eq!(glob.get(ctx), &"shared value");
/// fn create_glob(app: &mut App) -> Glob<&'static str> {
/// let glob = Glob::new(app, "shared value");
/// assert_eq!(glob.get(app), &"shared value");
/// glob
/// }
/// ```
Expand All @@ -42,11 +42,11 @@ where
T: 'static,
{
/// Creates a new shared `value`.
pub fn new(ctx: &mut Context<'_>, value: T) -> Self {
let globals = ctx.handle::<Globals<T>>();
pub fn new(app: &mut App, value: T) -> Self {
let globals = app.handle::<Globals<T>>();
Self {
ref_: GlobRef {
index: globals.get_mut(ctx).register(value).into(),
index: globals.get_mut(app).register(value).into(),
globals,
phantom: PhantomData,
},
Expand All @@ -64,13 +64,13 @@ where
}

/// Returns an immutable reference to the shared value.
pub fn get<'a>(&self, ctx: &'a Context<'_>) -> &'a T {
&self.ref_.globals.get(ctx)[self.index()]
pub fn get<'a>(&self, app: &'a App) -> &'a T {
&self.ref_.globals.get(app)[self.index()]
}

/// Returns a mutable reference to the shared value.
pub fn get_mut<'a>(&self, ctx: &'a mut Context<'_>) -> &'a mut T {
self.ref_.globals.get_mut(ctx).items[self.index()]
pub fn get_mut<'a>(&self, app: &'a mut App) -> &'a mut T {
self.ref_.globals.get_mut(app).items[self.index()]
.as_mut()
.expect("internal error: invalid index")
}
Expand All @@ -92,10 +92,10 @@ impl<T> AsRef<GlobRef<T>> for Glob<T> {
/// ```
/// # use modor::*;
/// #
/// fn create_glob_ref(ctx: &mut Context<'_>) -> GlobRef<&'static str> {
/// let glob = Glob::new(ctx, "shared value");
/// fn create_glob_ref(app: &mut App) -> GlobRef<&'static str> {
/// let glob = Glob::new(app, "shared value");
/// let ref_ = glob.as_ref().clone();
/// assert_eq!(ref_.get(ctx), &"shared value");
/// assert_eq!(ref_.get(app), &"shared value");
/// ref_
/// }
/// ```
Expand Down Expand Up @@ -129,8 +129,8 @@ where
}

/// Returns an immutable reference to the shared value.
pub fn get<'a>(&self, ctx: &'a Context<'_>) -> &'a T {
&self.globals.get(ctx)[self.index.index]
pub fn get<'a>(&self, app: &'a App) -> &'a T {
&self.globals.get(app)[self.index.index]
}
}

Expand All @@ -141,8 +141,8 @@ where
/// ```
/// # use modor::*;
/// #
/// fn access_glob(ctx: &mut Context<'_>, index: usize) -> &'static str {
/// ctx.get_mut::<Globals<&'static str>>()[index]
/// fn access_glob(app: &mut App, index: usize) -> &'static str {
/// app.get_mut::<Globals<&'static str>>()[index]
/// }
/// ```
#[derive(Debug)]
Expand All @@ -156,7 +156,7 @@ impl<T> RootNode for Globals<T>
where
T: 'static,
{
fn on_create(_ctx: &mut Context<'_>) -> Self {
fn on_create(_app: &mut App) -> Self {
Self {
indexes: Arc::default(),
items: vec![],
Expand All @@ -166,7 +166,7 @@ where
}

impl<T> Node for Globals<T> {
fn on_enter(&mut self, _ctx: &mut Context<'_>) {
fn on_enter(&mut self, _app: &mut App) {
self.indexes
.free_indexes(self.deleted_items.iter().map(|(i, _)| *i));
self.deleted_items.clear();
Expand All @@ -182,7 +182,7 @@ impl<T> Node for Globals<T> {
}

impl<T> Visit for Globals<T> {
fn visit(&mut self, _ctx: &mut Context<'_>) {}
fn visit(&mut self, _app: &mut App) {}
}

impl<T> Globals<T> {
Expand Down
8 changes: 4 additions & 4 deletions crates/modor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@
//! }
//!
//! impl RootNode for Root {
//! fn on_create(ctx: &mut Context<'_>) -> Self {
//! fn on_create(app: &mut App) -> Self {
//! Self {
//! counter: Counter::default()
//! }
//! }
//! }
//!
//! impl Node for Root {
//! fn on_enter(&mut self, ctx: &mut Context<'_>) {
//! fn on_enter(&mut self, app: &mut App) {
//! println!("Update counter...");
//! }
//!
//! fn on_exit(&mut self, ctx: &mut Context<'_>) {
//! fn on_exit(&mut self, app: &mut App) {
//! println!("Counter updated, new value is {}", self.counter.value);
//! }
//! }
Expand All @@ -51,7 +51,7 @@
//! }
//!
//! impl Node for Counter {
//! fn on_enter(&mut self, ctx: &mut Context<'_>) {
//! fn on_enter(&mut self, app: &mut App) {
//! self.value += 1;
//! }
//! }
Expand Down
10 changes: 5 additions & 5 deletions crates/modor/src/macro_utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Context, Node};
use crate::{App, Node};

pub struct MaybeNode<'a, T>(pub &'a mut T);

Expand All @@ -7,18 +7,18 @@ where
T: Node,
{
#[inline]
pub fn update(&mut self, ctx: &mut Context<'_>) {
Node::update(self.0, ctx);
pub fn update(&mut self, app: &mut App) {
Node::update(self.0, app);
}
}

pub trait NotNode {
fn update(&mut self, ctx: &mut Context<'_>);
fn update(&mut self, app: &mut App);
}

impl<T> NotNode for MaybeNode<'_, T> {
#[inline]
fn update(&mut self, _ctx: &mut Context<'_>) {
fn update(&mut self, _app: &mut App) {
// do nothing
}
}
Loading

0 comments on commit 60c4c94

Please sign in to comment.