diff --git a/Cargo.lock b/Cargo.lock index 63fd5bd..989be25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,7 +107,7 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "node_tree" -version = "0.6.5" +version = "0.7.0" dependencies = [ "chrono", "node_tree_derive", diff --git a/dynamic_logger.png b/dynamic_logger.png index 2f1eebb..0f8557c 100644 Binary files a/dynamic_logger.png and b/dynamic_logger.png differ diff --git a/node_tree_core/Cargo.toml b/node_tree_core/Cargo.toml index 8da51da..d4d0d06 100644 --- a/node_tree_core/Cargo.toml +++ b/node_tree_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node_tree" -version = "0.6.5" +version = "0.7.0" edition = "2021" rust-version = "1.78" diff --git a/node_tree_core/dynamic_logger.png b/node_tree_core/dynamic_logger.png index 2f1eebb..0f8557c 100644 Binary files a/node_tree_core/dynamic_logger.png and b/node_tree_core/dynamic_logger.png differ diff --git a/node_tree_core/src/lib.rs b/node_tree_core/src/lib.rs index 63acd08..fcf206f 100644 --- a/node_tree_core/src/lib.rs +++ b/node_tree_core/src/lib.rs @@ -60,6 +60,7 @@ pub mod prelude { node_tree_base::{ NodeTreeBase, TreeStatus, TreeProcess, ProcessMode, initialize_base }, tree_pointer::{ Tp, TpDyn }, tree_option::TreeOption, + tree_result::TreeResult, node_scene::NodeScene, rid::RID, }; diff --git a/node_tree_core/src/structs/node_base.rs b/node_tree_core/src/structs/node_base.rs index d9e3073..99d7190 100644 --- a/node_tree_core/src/structs/node_base.rs +++ b/node_tree_core/src/structs/node_base.rs @@ -32,7 +32,7 @@ use super::{ node_path::NodePath, node_tree_base::NodeTreeBase, tree_pointer::{ Tp, TpDyn }, - tree_option::TreeOption, + tree_result::TreeResult, rid::RID }; @@ -250,18 +250,18 @@ impl NodeBase { } /// Returns a `Tp` pointer to a child at the given index. - /// If there is no child at the given index, or if the wrong type is given, then `None` will be returned. + /// If there is no child at the given index, or if the wrong type is given, then `Err` will be returned. /// /// # Panics /// Panics if this Node is not connected to a `NodeTree`. - pub fn get_child(&self, i: usize) -> TreeOption> { + pub fn get_child(&self, i: usize) -> TreeResult> { if self.tree().is_none() { panic!("Cannot get a node from a node that is not a part of a NodeTree!"); } if i >= self.num_children() { unsafe { - TreeOption::new(self.tree.unwrap_unchecked(), self.rid, None) + TreeResult::new(self.tree.unwrap_unchecked(), self.rid, Err(format!("Index {i} was out of the range of this node's children count of {}", self.num_children()))) } } else { unsafe { @@ -271,18 +271,18 @@ impl NodeBase { } /// Returns a `TpDyn` pointer to a child at the given index. - /// If there is no child at the given index then `None` will be returned. + /// If there is no child at the given index then `Err` will be returned. /// /// # Panics /// Panics if this Node is not connected to a `NodeTree`. - pub fn get_child_dyn(&self, i: usize) -> TreeOption { + pub fn get_child_dyn(&self, i: usize) -> TreeResult { if self.tree().is_none() { panic!("Cannot get a node from a node that is not a part of a NodeTree!"); } if i >= self.num_children() { unsafe { - TreeOption::new(self.tree.unwrap_unchecked(), self.rid, None) + TreeResult::new(self.tree.unwrap_unchecked(), self.rid, Err(format!("Index {i} was out of the range of this node's children count of {}", self.num_children()))) } } else { unsafe { @@ -304,61 +304,62 @@ impl NodeBase { } /// Gets a `Tp` or a Tree Pointer to a given `Node` via a `NodePath`. - /// Returns `None` if the address is invalid or if the referenced `Node` is not of the type + /// Returns `Err` if the address is invalid or if the referenced `Node` is not of the type /// `T`. /// /// # Panics /// Panics if this Node is not connected to a `NodeTree`. - pub fn get_node(&self, path: NodePath) -> TreeOption> { + pub fn get_node(&self, path: NodePath) -> TreeResult> { if self.tree().is_none() { panic!("Cannot get a node from a node that is not a part of a NodeTree!"); } - match self.get_node_raw(path) { + match self.get_node_raw(path.clone()) { Some(node_rid) => { unsafe { Tp::new(self.tree.unwrap_unchecked(), self.rid, node_rid) } }, None => unsafe { - TreeOption::new(self.tree.unwrap_unchecked(), self.rid, None) + TreeResult::new(self.tree.unwrap_unchecked(), self.rid, Err(format!("The path {path:?} is invalid"))) } } } /// Gets a `TpDyn` or a Dynamic Tree Pointer to a given `Node` via a `NodePath`. - /// Returns `None` if the address is invalid. + /// Returns `Err` if the address is invalid. /// /// # Panics /// Panics if this Node is not connected to a `NodeTree`. - pub fn get_node_dyn(&self, path: NodePath) -> TreeOption { + pub fn get_node_dyn(&self, path: NodePath) -> TreeResult { if self.tree().is_none() { panic!("Cannot get a node from a node that is not a part of a NodeTree!"); } - match self.get_node_raw(path) { + match self.get_node_raw(path.clone()) { Some(node_rid) => { unsafe { TpDyn::new(self.tree.unwrap_unchecked(), self.rid, node_rid) } }, None => unsafe { - TreeOption::new(self.tree.unwrap_unchecked(), self.rid, None) + TreeResult::new(self.tree.unwrap_unchecked(), self.rid, Err(format!("The path {path:?} is invalid"))) } } } /// Gets a `Tp` or a Tree Pointer to a given `Node` via either a `NodePath`, a `&str`, or a /// String (the latter two may be used to denote Singletons). - /// Returns `None` if the address is invalid or if the referenced `Node` is not of the type + /// Returns `Err` if the address is invalid or if the referenced `Node` is not of the type /// `T`. /// /// # Panics /// Panics if this Node is not connected to a `NodeTree`. - pub fn get_node_from_tree(&self, path: G) -> TreeOption> { + pub fn get_node_from_tree(&self, path: G) -> TreeResult> { if self.tree().is_none() { panic!("Cannot get a node from a node that is not a part of a NodeTree!"); } + let path_str: String = format!("{path:?}"); match unsafe { self.tree().unwrap_unchecked() }.get_node_rid(path) { Some(node_rid) => { @@ -367,21 +368,22 @@ impl NodeBase { } }, None => unsafe { - TreeOption::new(self.tree.unwrap_unchecked(), self.rid, None) + TreeResult::new(self.tree.unwrap_unchecked(), self.rid, Err(format!("The root path {path_str:?} is invalid"))) } } } /// Gets a `TpDyn` or a Dynamic Tree Pointer to a given `Node` via either a `NodePath`, a `&str`, or a /// String (the latter two may be used to denote Singletons). - /// Returns `None` if the address is invalid. + /// Returns `Err` if the address is invalid. /// /// # Panics /// Panics if this Node is not connected to a `NodeTree`. - pub fn get_node_dyn_from_tree(&self, path: G) -> TreeOption { + pub fn get_node_dyn_from_tree(&self, path: G) -> TreeResult { if self.tree().is_none() { panic!("Cannot get a node from a node that is not a part of a NodeTree!"); } + let path_str: String = format!("{path:?}"); match unsafe { self.tree().unwrap_unchecked() }.get_node_rid(path) { Some(node_rid) => { @@ -390,7 +392,7 @@ impl NodeBase { } }, None => unsafe { - TreeOption::new(self.tree.unwrap_unchecked(), self.rid, None) + TreeResult::new(self.tree.unwrap_unchecked(), self.rid, Err(format!("The root path {path_str:?} is invalid"))) } } } @@ -584,7 +586,7 @@ impl NodeBase { self.tree = None; } - /// Gets the `Tp` owner of the node. Returns None if `T` does not match the owner's type. + /// Gets the `Tp` owner of the node. Returns `Err` if `T` does not match the owner's type. /// The owner is different from the parent. The owner can be thought as the root of the scene /// that this node is a part of, rather than the node's actual parent. /// In other words, if you had a node tree that looked like this: @@ -602,7 +604,7 @@ impl NodeBase { /// /// # Panics /// Panics if this Node is not connected to a `NodeTree`. - pub fn owner(&self) -> TreeOption> { + pub fn owner(&self) -> TreeResult> { if self.tree().is_none() { panic!("Cannot get a node from a node that is not a part of a NodeTree!"); } @@ -651,11 +653,11 @@ impl NodeBase { } /// Gets a `Tp` pointer to the direct parent of this node, if the node has one. - /// Returns `None` if there is no parent or if `T` does not match the parent's type. + /// Returns `Err` if there is no parent or if `T` does not match the parent's type. /// /// # Panics /// Panics if this Node is not connected to a `NodeTree`. - pub fn parent(&self) -> TreeOption> { + pub fn parent(&self) -> TreeResult> { if self.tree().is_none() { panic!("Cannot get a node from a node that is not a part of a NodeTree!"); } @@ -667,17 +669,17 @@ impl NodeBase { } }, None => unsafe { - TreeOption::new(self.tree.unwrap_unchecked(), self.rid, None) + TreeResult::new(self.tree.unwrap_unchecked(), self.rid, Err("This node has no parent".to_string())) } } } /// Gets a `TpDyn` pointer to the direct parent of this node, if the node has one. - /// Returns `None` if there is no parent. + /// Returns `Err` if there is no parent. /// /// # Panics /// Panics if this Node is not connected to a `NodeTree`. - pub fn parent_dyn(&self) -> TreeOption { + pub fn parent_dyn(&self) -> TreeResult { if self.tree().is_none() { panic!("Cannot get a node from a node that is not a part of a NodeTree!"); } @@ -689,7 +691,7 @@ impl NodeBase { } }, None => unsafe { - TreeOption::new(self.tree.unwrap_unchecked(), self.rid, None) + TreeResult::new(self.tree.unwrap_unchecked(), self.rid, Err("This node has no parent".to_string())) } } } diff --git a/node_tree_core/src/structs/node_path.rs b/node_tree_core/src/structs/node_path.rs index a2c666d..f74317f 100644 --- a/node_tree_core/src/structs/node_path.rs +++ b/node_tree_core/src/structs/node_path.rs @@ -41,6 +41,7 @@ //! } //! ``` +use std::fmt::{self, Write}; use std::collections::VecDeque; use crate::traits::node_getter::NodeGetter; @@ -49,7 +50,7 @@ use super::{ node_tree_base::NodeTreeBase, rid::RID }; /// A NodePath is a specialized string that holds a map for the NodeTree to follow and to retrieve /// a given node. -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct NodePath { path: VecDeque } @@ -104,3 +105,13 @@ impl NodeGetter for NodePath { tree.root().get_node_raw(absolute_path) } } + +impl fmt::Debug for NodePath { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut path: String = self.path.iter().map(|node| "/".to_owned() + node).collect(); + path = "'".to_string() + &path + "'"; + + f.write_str(&path)?; + Ok(()) + } +} diff --git a/node_tree_core/src/structs/tree_option.rs b/node_tree_core/src/structs/tree_option.rs index e4f737f..99abe9f 100644 --- a/node_tree_core/src/structs/tree_option.rs +++ b/node_tree_core/src/structs/tree_option.rs @@ -1,3 +1,31 @@ +//===================================================================================================================================================================================// +// +// /$$$$$$$$ /$$$$$$ /$$ /$$ +// |__ $$__/ /$$__ $$ | $$ |__/ +// | $$ /$$$$$$ /$$$$$$ /$$$$$$ | $$ \ $$ /$$$$$$ /$$$$$$ /$$ /$$$$$$ /$$$$$$$ +// | $$ /$$__ $$ /$$__ $$ /$$__ $$ | $$ | $$ /$$__ $$|_ $$_/ | $$ /$$__ $$| $$__ $$ +// | $$| $$ \__/| $$$$$$$$| $$$$$$$$ | $$ | $$| $$ \ $$ | $$ | $$| $$ \ $$| $$ \ $$ +// | $$| $$ | $$_____/| $$_____/ | $$ | $$| $$ | $$ | $$ /$$| $$| $$ | $$| $$ | $$ +// | $$| $$ | $$$$$$$| $$$$$$$ | $$$$$$/| $$$$$$$/ | $$$$/| $$| $$$$$$/| $$ | $$ +// |__/|__/ \_______/ \_______/ \______/ | $$____/ \___/ |__/ \______/ |__/ |__/ +// | $$ +// | $$ +// |__/ +// +//===================================================================================================================================================================================// + +//? +//? Created by LunaticWyrm467 and others. +//? +//? All code is licensed under the MIT license. +//? Feel free to reproduce, modify, and do whatever. +//? + +//! +//! Implements a counterpart to the standard library's `Option` which enables for option-like +//! dynamics with error reporting that is tied into the current node tree and logger. +//! + use std::mem; use std::hint::unreachable_unchecked; use std::marker::PhantomData; @@ -7,14 +35,15 @@ use std::option::{ Iter, IterMut }; use crate::traits::node_tree::NodeTree; use super::rid::RID; use super::logger::Log; +use super::tree_result::TreeResult; /// A simple counterpart to the standard library's `Option`, which has a few extra features such as /// logging panics or undesired behaviours to the log. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TreeOption<'a, T> { - owner: RID, tree: *mut dyn NodeTree, + owner: RID, object: Option, p_life: PhantomData<&'a ()> } @@ -28,8 +57,8 @@ impl <'a, T> TreeOption<'a, T> { /// Instead of constructing this type yourself, it is best to only use it when a node function /// constructs it for you. #[inline] - pub unsafe fn new(tree: *mut dyn NodeTree, owner: RID, object: Option) -> Self { - TreeOption { owner, tree, object, p_life: PhantomData } + pub const unsafe fn new(tree: *mut dyn NodeTree, owner: RID, object: Option) -> Self { + TreeOption { tree, owner, object, p_life: PhantomData } } /// Converts this to an `Option` type. @@ -56,7 +85,7 @@ impl <'a, T> TreeOption<'a, T> { self.object.is_none() } - ///// Returns `true` if the option is a [`None`] or the value inside of it matches a predicate. + ///// Returns `true` if the option is a `None` or the value inside of it matches a predicate. //#[inline] //pub fn is_none_or(&self, f: impl FnOnce(&T) -> bool) -> bool { // self.object.as_ref().is_none_or(f) @@ -65,13 +94,13 @@ impl <'a, T> TreeOption<'a, T> { /// Converts from `&Option` to `Option<&T>`. #[inline] pub const fn as_ref(&self) -> TreeOption<&T> { - TreeOption { owner: self.owner, tree: self.tree, object: self.object.as_ref(), p_life: self.p_life } + TreeOption { tree: self.tree, owner: self.owner, object: self.object.as_ref(), p_life: self.p_life } } /// Converts from `&mut Option` to `Option<&mut T>`. #[inline] pub fn as_mut(&mut self) -> TreeOption<&mut T> { - TreeOption { owner: self.owner, tree: self.tree, object: self.object.as_mut(), p_life: self.p_life } + TreeOption { tree: self.tree, owner: self.owner, object: self.object.as_mut(), p_life: self.p_life } } /// Returns a slice of the contained value, if any. If this is `None`, an @@ -115,8 +144,12 @@ impl <'a, T> TreeOption<'a, T> { /// /// Because this function may panic, its use is generally discouraged. /// Instead, prefer to use pattern matching and handle the `None` - /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or - /// [`unwrap_or_default`]. + /// case explicitly, or call `unwrap_or`, `unwrap_or_else`, or + /// `unwrap_or_default`. + /// + /// # Panics + /// + /// Panics if the self value equals `None`. #[inline(always)] pub fn unwrap(self) -> T { match self.object { @@ -150,7 +183,7 @@ impl <'a, T> TreeOption<'a, T> { /// Returns the contained `Some` value or a default. /// /// Consumes the `self` argument then, if `Some`, returns the contained - /// value, otherwise if `None`, returns the [default value] for that + /// value, otherwise if `None`, returns the default value for that /// type. pub fn unwrap_or_default(self) -> T where @@ -173,10 +206,10 @@ impl <'a, T> TreeOption<'a, T> { } } - /// Maps an `Option` to `Option` by applying a function to a contained value (if `Some`) or returns `None` (if `None`). + /// Maps an `TreeOption` to `TreeOption` by applying a function to a contained value (if `Some`) or returns `None` (if `None`). #[inline] pub fn map U>(self, f: F) -> TreeOption<'a, U> { - TreeOption { owner: self.owner, tree: self.tree, object: self.object.map(f), p_life: self.p_life } + TreeOption { tree: self.tree, owner: self.owner, object: self.object.map(f), p_life: self.p_life } } /// Calls a function with a reference to the contained value if `Some`. @@ -187,7 +220,6 @@ impl <'a, T> TreeOption<'a, T> { if let Some(ref x) = self.object { f(x); } - self } @@ -211,42 +243,46 @@ impl <'a, T> TreeOption<'a, T> { F: FnOnce(T) -> U, { self.object.map_or_else(default, f) } - /// Transforms the `Option` into a `Result`, mapping `Some(v)` to + /// Transforms the `TreeOption` into a `TreeResult`, mapping `Some(v)` to /// `Ok(v)` and `None` to `Err(err)`. /// /// Arguments passed to `ok_or` are eagerly evaluated; if you are passing the /// result of a function call, it is recommended to use `ok_or_else`, which is /// lazily evaluated. #[inline] - pub fn ok_or(self, err: E) -> Result { - self.object.ok_or(err) + pub fn ok_or(self, err: String) -> TreeResult<'a, T> { + unsafe { + TreeResult::new(self.tree, self.owner, self.object.ok_or(err)) + } } - /// Transforms the `Option` into a `Result`, mapping `Some(v)` to + /// Transforms the `TreeOption` into a `TreeResult`, mapping `Some(v)` to /// `Ok(v)` and `None` to `Err(err())`. - pub fn ok_or_else E>(self, err: F) -> Result { - self.object.ok_or_else(err) + pub fn ok_or_else String>(self, err: F) -> TreeResult<'a, T> { + unsafe { + TreeResult::new(self.tree, self.owner, self.object.ok_or_else(err)) + } } - /// Converts from `Option` (or `&Option`) to `Option<&T::Target>`. + /// Converts from `TreeOption` (or `&TreeOption`) to `TreeOption<&T::Target>`. /// /// Leaves the original `Option` in-place, creating a new one with a reference /// to the original one, additionally coercing the contents via `Deref`. #[inline] - pub fn as_deref(&self) -> Option<&T::Target> + pub fn as_deref(&self) -> TreeOption<&T::Target> where T: Deref, - { self.object.as_deref() } + { self.as_another(self.object.as_deref()) } - /// Converts from `Option` (or `&mut Option`) to `Option<&mut T::Target>`. + /// Converts from `TreeOption` (or `&mut TreeOption`) to `TreeOption<&mut T::Target>`. /// /// Leaves the original `Option` in-place, creating a new one containing a mutable reference to /// the inner type's `Deref::Target` type. #[inline] - pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> + pub fn as_deref_mut(&mut self) -> TreeOption<&mut T::Target> where T: DerefMut, - { self.object.as_deref_mut() } + { TreeOption { tree: self.tree, owner: self.owner, object: self.object.as_deref_mut(), p_life: self.p_life } } /// Returns an iterator over the possibly contained value. #[inline] @@ -266,10 +302,10 @@ impl <'a, T> TreeOption<'a, T> { /// result of a function call, it is recommended to use `and_then`, which is /// lazily evaluated. #[inline] - pub fn and<'b, U>(self, optb: TreeOption<'b, U>) -> TreeOption<'b, U> { + pub fn and<'b, U>(self, optb: TreeOption<'b, U>) -> TreeOption<'a, U> { match self.object { - Some(_) => optb, - None => TreeOption { owner: self.owner, tree: self.tree, object: None, p_life: optb.p_life } + Some(_) => self.transfer_owner(optb), + None => self.as_none() } } @@ -279,10 +315,10 @@ impl <'a, T> TreeOption<'a, T> { /// Some languages call this operation flatmap. #[inline] #[doc(alias = "flatmap")] - pub fn and_then<'b, U, F: FnOnce(T) -> TreeOption<'b, U>>(self, f: F) -> TreeOption<'b, U> { + pub fn and_then<'b, U, F: FnOnce(T) -> TreeOption<'b, U>>(self, f: F) -> TreeOption<'a, U> { match self.object { - Some(x) => f(x), - None => TreeOption { owner: self.owner, tree: self.tree, object: None, p_life: PhantomData } + Some(x) => TreeOption { tree: self.tree, owner: self.owner, object: f(x).to_option(), p_life: self.p_life }, + None => TreeOption { tree: self.tree, owner: self.owner, object: None, p_life: self.p_life } } } @@ -294,7 +330,7 @@ impl <'a, T> TreeOption<'a, T> { /// - `None` if `predicate` returns `false`. /// /// This function works similar to `Iterator::filter()`. You can imagine - /// the `Option` being an iterator over one or zero elements. `filter()` + /// the `TreeOption` being an iterator over one or zero elements. `filter()` /// lets you decide which elements to keep. #[inline] pub fn filter bool>(self, predicate: P) -> Self { @@ -311,30 +347,30 @@ impl <'a, T> TreeOption<'a, T> { /// Arguments passed to `or` are eagerly evaluated; if you are passing the /// result of a function call, it is recommended to use `or_else`, which is /// lazily evaluated. - pub fn or(self, optb: TreeOption<'a, T>) -> TreeOption<'a, T> { + pub fn or<'b>(self, optb: TreeOption<'b, T>) -> TreeOption<'a, T> { match self.object { - x @ Some(_) => TreeOption { owner: self.owner, tree: self.tree, object: x, p_life: self.p_life }, - None => optb + object @ Some(_) => TreeOption { tree: self.tree, owner: self.owner, object, p_life: self.p_life }, + None => self.transfer_owner(optb) } } /// Returns the option if it contains a value, otherwise calls `f` and /// returns the result. #[inline] - pub fn or_else TreeOption<'a, T>>(self, f: F) -> TreeOption<'a, T> { + pub fn or_else<'b, F: FnOnce() -> TreeOption<'b, T>>(self, f: F) -> TreeOption<'a, T> { match self.object { - x @ Some(_) => TreeOption { owner: self.owner, tree: self.tree, object: x, p_life: self.p_life }, - None => f(), + object @ Some(_) => TreeOption { tree: self.tree, owner: self.owner, object, p_life: self.p_life }, + None => self.transfer_owner(f()), } } /// Returns `Some` if exactly one of `self`, `optb` is `Some`, otherwise returns `None`. #[inline] - pub fn xor(self, optb: TreeOption<'a, T>) -> TreeOption<'a, T> { + pub fn xor<'b>(self, optb: TreeOption<'b, T>) -> TreeOption<'a, T> { match (self.object, optb.object) { - (a @ Some(_), None) => TreeOption { owner: self.owner, tree: self.tree, object: a, p_life: self.p_life }, - (None, b @ Some(_)) => TreeOption { owner: self.owner, tree: self.tree, object: b, p_life: self.p_life }, - _ => TreeOption { owner: self.owner, tree: self.tree, object: None, p_life: self.p_life } + (opta @ Some(_), None) => TreeOption { tree: self.tree, owner: self.owner, object: opta, p_life: self.p_life }, + (None, optb @ Some(_)) => TreeOption { tree: self.tree, owner: self.owner, object: optb, p_life: self.p_life }, + _ => TreeOption { tree: self.tree, owner: self.owner, object: None, p_life: self.p_life } } } @@ -400,8 +436,8 @@ impl <'a, T> TreeOption<'a, T> { #[inline] pub fn take_if bool>(&mut self, predicate: P) -> TreeOption { TreeOption { - owner: self.owner, tree: self.tree, + owner: self.owner, object: if self.as_mut().map_or(false, predicate) { self.object.take() } else { None }, p_life: self.p_life } @@ -415,14 +451,14 @@ impl <'a, T> TreeOption<'a, T> { mem::replace(&mut self.object, Some(value)) } - /// Zips `self` with another `Option`. + /// Zips `self` with another `TreeOption`. /// /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`. /// Otherwise, `None` is returned. - pub fn zip(self, other: TreeOption<'a, U>) -> TreeOption<'a, (T, U)> { + pub fn zip<'b, U>(self, other: TreeOption<'b, U>) -> TreeOption<'a, (T, U)> { TreeOption { - owner: self.owner, tree: self.tree, + owner: self.owner, object: self.object.zip(other.object), p_life: self.p_life } @@ -434,13 +470,18 @@ impl <'a, T> TreeOption<'a, T> { /// Otherwise, `None` is returned. pub fn zip_with R>(self, other: TreeOption<'a, U>, f: F) -> TreeOption<'a, R> { TreeOption { - owner: self.owner, tree: self.tree, + owner: self.owner, object: self.object.zip_with(other.object, f), p_life: self.p_life } }*/ + /// Gives another `TreeOption` the same node owner as this one. + pub fn transfer_owner<'b, U>(&self, other: TreeOption<'b, U>) -> TreeOption<'a, U> { + TreeOption { tree: self.tree, owner: self.owner, object: other.object, p_life: self.p_life} + } + /// Marks a failed operation with a panic on the log, and panics the main thread. fn fail(&self, msg: &str) -> ! { unsafe { (&mut *self.tree).get_node(self.owner).unwrap_unchecked() }.post(Log::Panic(msg)); @@ -448,16 +489,22 @@ impl <'a, T> TreeOption<'a, T> { panic!(); } + /// Creates a `TreeOption` with all of the calling `TreeOption`'s metadata attached and the + /// given optional item as its value. + fn as_another(&self, object: Option) -> TreeOption<'a, U> { + TreeOption { tree: self.tree, owner: self.owner, object, p_life: self.p_life } + } + /*/// Creates a `TreeOption` with all of the calling `TreeOption`'s metadata attached and the /// given item as its value. fn as_some(&self, object: U) -> TreeOption<'a, U> { - TreeOption { owner: self.owner, tree: self.tree, object: Some(object), p_life: self.p_life } + TreeOption { tree: self.tree, owner: self.owner, object: Some(object), p_life: self.p_life } }*/ /// Creates a `TreeOption` with all of the calling `TreeOption`'s metadata attached and `None` /// as its value. fn as_none(&self) -> TreeOption<'a, U> { - TreeOption { owner: self.owner, tree: self.tree, object: None, p_life: self.p_life } + TreeOption { tree: self.tree, owner: self.owner, object: None, p_life: self.p_life } } } @@ -471,13 +518,13 @@ impl <'a, T, U> TreeOption<'a, (T, U)> { pub fn unzip(self) -> (TreeOption<'a, T>, TreeOption<'a, U>) { match self.object { Some((a, b)) => (TreeOption { - owner: self.owner, tree: self.tree, + owner: self.owner, object: Some(a), p_life: self.p_life }, TreeOption { - owner: self.owner, tree: self.tree, + owner: self.owner, object: Some(b), p_life: self.p_life }), @@ -488,14 +535,14 @@ impl <'a, T, U> TreeOption<'a, (T, U)> { impl <'a, T> TreeOption<'a, &T> { - /// Maps an `Option<&T>` to an `Option` by copying the contents of the + /// Maps an `TreeOption<&T>` to an `TreeOption` by copying the contents of the /// option. pub fn copied(self) -> TreeOption<'a, T> where T: Copy, { self.map(|x| *x) } - /// Maps an `Option<&T>` to an `Option` by cloning the contents of the + /// Maps an `TreeOption<&T>` to an `TreeOption` by cloning the contents of the /// option. pub fn cloned(self) -> TreeOption<'a, T> where @@ -505,17 +552,49 @@ impl <'a, T> TreeOption<'a, &T> { impl <'a, T> TreeOption<'a, &mut T> { - /// Maps an `Option<&mut T>` to an `Option` by copying the contents of the + /// Maps an `TreeOption<&mut T>` to an `TreeOption` by copying the contents of the /// option. pub fn copied(self) -> TreeOption<'a, T> where T: Copy, { self.map(|x| *x) } - /// Maps an `Option<&mut T>` to an `Option` by cloning the contents of the + /// Maps an `TreeOption<&mut T>` to an `TreeOption` by cloning the contents of the /// option. pub fn cloned(self) -> TreeOption<'a, T> where T: Clone, { self.map(|x| x.to_owned()) } } + +impl <'a, 'b, T> TreeOption<'a, TreeResult<'b, T>> { + + /// Transposes an `TreeOption` of a `TreeResult` into a `TreeResult` of an `TreeOption`. + /// + /// `None` will be mapped to Ok\(None). + /// Some\(Ok\(\_)) and Some\(Err\(\_)) will be mapped to + /// Ok\(Some\(\_)) and Err\(\_). + #[inline] + pub fn transpose(self) -> TreeResult<'a, TreeOption<'a, T>> { + match self.object { + Some(inner) => { + match inner.to_result() { + Ok(x) => unsafe { TreeResult::new(self.tree, self.owner, Ok(TreeOption::new(self.tree, self.owner, Some(x)))) }, + Err(e) => unsafe { TreeResult::new(self.tree, self.owner, Err(e)) }, + } + }, + None => unsafe { TreeResult::new(self.tree, self.owner, Ok(TreeOption::new(self.tree, self.owner, None))) } + } + } +} + +impl <'a, 'b, T> TreeOption<'a, TreeOption<'b, T>> { + + /// Converts from `TreeOption>` to `TreeOption`. + pub fn flatten(self) -> TreeOption<'a, T> { + match self.object { + Some(object) => TreeOption { tree: self.tree, owner: self.owner, object: object.to_option(), p_life: self.p_life }, + None => self.as_none() + } + } +} diff --git a/node_tree_core/src/structs/tree_pointer.rs b/node_tree_core/src/structs/tree_pointer.rs index c713eeb..cd4bbae 100644 --- a/node_tree_core/src/structs/tree_pointer.rs +++ b/node_tree_core/src/structs/tree_pointer.rs @@ -34,6 +34,7 @@ use crate::traits::{ node::Node, node_tree::NodeTree }; use super::rid::RID; use super::logger::Log; use super::tree_option::TreeOption; +use super::tree_result::TreeResult; /* @@ -54,9 +55,9 @@ use super::tree_option::TreeOption; /// versions of `get()` and `get_mut()`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Tp<'a, T: Node> { + tree: *mut dyn NodeTree, owner: RID, node: RID, - tree: *mut dyn NodeTree, p_life: PhantomData<&'a ()>, p_type: PhantomData } @@ -74,7 +75,7 @@ impl <'a, T: Node> Tp<'a, T> { /// # Failure /// Will not return a valid `Tp` pointer if the types do not match, or if the referenced /// `Node` is invalid! - pub unsafe fn new(tree: *mut dyn NodeTree, owner: RID, node: RID) -> TreeOption<'a, Self> { + pub unsafe fn new(tree: *mut dyn NodeTree, owner: RID, node: RID) -> TreeResult<'a, Self> { // First check if the types match using dynamic dispatch! match (&*tree).get_node(node) { @@ -82,16 +83,16 @@ impl <'a, T: Node> Tp<'a, T> { let any: &dyn Any = node.as_any(); match any.downcast_ref::() { Some(_) => (), - None => return TreeOption::new(tree, owner, None) + None => return TreeResult::new(tree, owner, Err("The node exists but ultimately is of the wrong type".to_string())) } }, - None => return TreeOption::new(tree, owner, None) + None => return TreeResult::new(tree, owner, Err("A non-existent node was referenced".to_string())) } - TreeOption::new(tree, owner, Some(Tp { + TreeResult::new(tree, owner, Ok(Tp { + tree, owner, node, - tree, p_life: PhantomData, p_type: PhantomData })) @@ -103,9 +104,9 @@ impl <'a, T: Node> Tp<'a, T> { /// Panics if the node is invalid! pub fn to_dyn(self) -> TpDyn<'a> { unsafe { - match TpDyn::new(self.tree, self.owner, self.node).to_option() { + match TpDyn::new(self.tree, self.owner, self.node).ok().to_option() { Some(success) => success, - None => self.fail("Cannot cast a null Tp to a dynamic TpDyn!") + None => self.fail("Cannot cast a null Tp to a dynamic TpDyn") } } } @@ -114,7 +115,7 @@ impl <'a, T: Node> Tp<'a, T> { /// /// # Failure /// Will not return a valid `TpDyn` pointer if the internally referenced `Node` has been invalidated! - pub fn try_to_dyn(self) -> TreeOption<'a, TpDyn<'a>> { + pub fn try_to_dyn(self) -> TreeResult<'a, TpDyn<'a>> { unsafe { TpDyn::new(self.tree, self.owner, self.node) } @@ -159,25 +160,25 @@ impl <'a, T: Node> Tp<'a, T> { let any: &dyn Any = node.as_any(); match any.downcast_ref::() { Some(node) => node, - None => self.fail("Invalid node!") + None => self.fail("The node exists but ultimately is of the wrong type") } }, - None => self.fail("Invalid Node!") + None => self.fail("A non-existent node was referenced") } } - /// Attempts to get a reference to the underlying `Node`. Returns `None` if the `Node` is invalid. - pub fn try_get(&self) -> TreeOption<&T> { + /// Attempts to get a reference to the underlying `Node`. Returns `Err` if the `Node` is invalid. + pub fn try_get(&self) -> TreeResult<&T> { let node: Option<&dyn Node> = unsafe { &*self.tree }.get_node_raw(self.node).map(|n| unsafe { &*n }); match node { Some(node) => { let any: &dyn Any = node.as_any(); match any.downcast_ref::() { - Some(node) => unsafe { TreeOption::new(self.tree, self.owner, Some(node)) }, - None => unsafe { TreeOption::new(self.tree, self.owner, None) } + Some(node) => unsafe { TreeResult::new(self.tree, self.owner, Ok(node)) }, + None => unsafe { TreeResult::new(self.tree, self.owner, Err("The node exists but ultimately is of the wrong type".to_string())) } } }, - None => unsafe { TreeOption::new(self.tree, self.owner, None) } + None => unsafe { TreeResult::new(self.tree, self.owner, Err("A non-existent node was referenced".to_string())) } } } @@ -192,25 +193,25 @@ impl <'a, T: Node> Tp<'a, T> { let any: &mut dyn Any = node.as_any_mut(); match any.downcast_mut::() { Some(node) => node, - None => self.fail("Invalid node!") + None => self.fail("The node exists but ultimately is of the wrong type") } }, - None => self.fail("Invalid Node!") + None => self.fail("A non-existent node was referenced") } } - /// Attempts to get a mutable reference to the underlying `Node`. Returns `None` if the `Node` is invalid. - pub fn try_get_mut(&mut self) -> TreeOption<&mut T> { + /// Attempts to get a mutable reference to the underlying `Node`. Returns `Err` if the `Node` is invalid. + pub fn try_get_mut(&mut self) -> TreeResult<&mut T> { let node: Option<&mut dyn Node> = unsafe { &mut *self.tree }.get_node_mut_raw(self.node).map(|n| unsafe { &mut *n }); match node { Some(node) => { let any: &mut dyn Any = node.as_any_mut(); match any.downcast_mut::() { - Some(node) => unsafe { TreeOption::new(self.tree, self.owner, Some(node)) }, - None => unsafe { TreeOption::new(self.tree, self.owner, None) } + Some(node) => unsafe { TreeResult::new(self.tree, self.owner, Ok(node)) }, + None => unsafe { TreeResult::new(self.tree, self.owner, Err("The node exists but ultimately is of the wrong type".to_string())) } } }, - None => unsafe { TreeOption::new(self.tree, self.owner, None) } + None => unsafe { TreeResult::new(self.tree, self.owner, Err("A non-existent node was referenced".to_string())) } } } @@ -276,15 +277,15 @@ impl <'a> TpDyn<'a> { /// /// # Failure /// Will not return a valid `TpDyn` pointer if the referenced `Node` is invalid! - pub unsafe fn new(tree: *mut dyn NodeTree, owner: RID, node: RID) -> TreeOption<'a, Self> { + pub unsafe fn new(tree: *mut dyn NodeTree, owner: RID, node: RID) -> TreeResult<'a, Self> { // First check if the node exists! match (&*tree).get_node(node) { Some(_) => (), - None => return TreeOption::new(tree, owner, None) + None => return TreeResult::new(tree, owner, Err("A non-existent node was referenced".to_string())) } - TreeOption::new(tree, owner, Some(TpDyn { + TreeResult::new(tree, owner, Ok(TpDyn { owner, node, tree, @@ -293,7 +294,7 @@ impl <'a> TpDyn<'a> { } /// Converts this to a type-coerced pointer. - pub fn to(self) -> TreeOption<'a, Tp<'a, T>> { + pub fn to(self) -> TreeResult<'a, Tp<'a, T>> { unsafe { Tp::new(self.tree, self.owner, self.node) } @@ -338,15 +339,15 @@ impl <'a> TpDyn<'a> { let node: Option<&dyn Node> = unsafe { &*self.tree }.get_node_raw(self.node).map(|n| unsafe { &*n }); match node { Some(node) => node, - None => self.fail("Invalid Node!") + None => self.fail("A non-existent node was referenced") } } - /// Attempts to get a reference to the underlying `Node`. Returns `None` if the `Node` is invalid. - pub fn try_get(&self) -> TreeOption<'a, &dyn Node> { + /// Attempts to get a reference to the underlying `Node`. Returns `Err` if the `Node` is invalid. + pub fn try_get(&self) -> TreeResult<'a, &dyn Node> { match unsafe { &*self.tree }.get_node_raw(self.node).map(|n| unsafe { &*n }) { - Some(node) => unsafe { TreeOption::new(self.tree, self.owner, Some(node)) }, - None => unsafe { TreeOption::new(self.tree, self.owner, None) } + Some(node) => unsafe { TreeResult::new(self.tree, self.owner, Ok(node)) }, + None => unsafe { TreeResult::new(self.tree, self.owner, Err("A non-existent node was referenced".to_string())) } } } @@ -358,15 +359,15 @@ impl <'a> TpDyn<'a> { let node: Option<&mut dyn Node> = unsafe { &mut *self.tree }.get_node_mut_raw(self.node).map(|n| unsafe { &mut *n }); match node { Some(node) => node, - None => self.fail("Invalid Node!") + None => self.fail("A non-existent node was referenced") } } - /// Attempts to get a mutable reference to the underlying `Node`. Returns `None` if the `Node` is invalid. - pub fn try_get_mut(&mut self) -> TreeOption<'a, &mut dyn Node> { + /// Attempts to get a mutable reference to the underlying `Node`. Returns `Err` if the `Node` is invalid. + pub fn try_get_mut(&mut self) -> TreeResult<'a, &mut dyn Node> { match unsafe { &mut *self.tree }.get_node_mut_raw(self.node).map(|n| unsafe { &mut *n }) { - Some(node) => unsafe { TreeOption::new(self.tree, self.owner, Some(node)) }, - None => unsafe { TreeOption::new(self.tree, self.owner, None) } + Some(node) => unsafe { TreeResult::new(self.tree, self.owner, Ok(node)) }, + None => unsafe { TreeResult::new(self.tree, self.owner, Err("A non-existent node was referenced".to_string())) } } } diff --git a/node_tree_core/src/structs/tree_result.rs b/node_tree_core/src/structs/tree_result.rs index e69de29..574b1b2 100644 --- a/node_tree_core/src/structs/tree_result.rs +++ b/node_tree_core/src/structs/tree_result.rs @@ -0,0 +1,484 @@ +use std::fmt; +use std::hint::unreachable_unchecked; +use std::marker::PhantomData; +use std::ops::{ Deref, DerefMut }; +use std::result::{ Iter, IterMut }; + +use crate::traits::node_tree::NodeTree; +use super::rid::RID; +use super::logger::Log; +use super::tree_option::TreeOption; + + +/// A simple counterpart to the standard library's `Result`, which has a few extra features such as +/// logging panics or undesired behaviours to the log. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[must_use = "this `Result` may be an `Err` variant, which should be handled"] +pub struct TreeResult<'a, T> { + tree: *mut dyn NodeTree, + owner: RID, + object: Result, + p_life: PhantomData<&'a ()> +} + +impl <'a, T> TreeResult<'a, T> { + + /// Creates a new `TreeResult`. + /// + /// # Safety + /// This is marked unsafe because it is unknown if the passed in tree pointer is valid. + /// Instead of constructing this type yourself, it is best to only use it when a node function + /// constructs it for you. + #[inline] + pub const unsafe fn new(tree: *mut dyn NodeTree, owner: RID, object: Result) -> Self { + TreeResult { owner, tree, object, p_life: PhantomData } + } + + /// Converts this to a `Result` type. + #[inline] + pub fn to_result(self) -> Result { + self.object + } + + + /// Converts this to an `Option` type. + #[inline] + pub fn to_option(self) -> Option { + self.object.ok() + } + + /// Returns `true` if the result is `Ok`. + #[inline] + pub const fn is_ok(&self) -> bool { + self.object.is_ok() + } + + /// Returns `true` if the result is `Ok` and the value inside of it matches a predicate. + #[inline] + pub fn is_ok_and(&self, f: impl FnOnce(&T) -> bool) -> bool { + self.object.as_ref().is_ok_and(f) + } + + /// Returns `true` if the result is `Err`. + #[inline] + pub const fn is_err(&self) -> bool { + !self.is_ok() + } + + /// Returns `true` if the result is `Err` and the value inside of it matches a predicate. + #[inline] + pub fn is_err_and(&self, f: impl FnOnce(&String) -> bool) -> bool { + self.object.as_ref().is_err_and(f) + } + + /// Converts from `TreeResult` to `TreeOption`. + /// + /// Converts `self` into an `TreeOption`, consuming `self`, + /// and discarding the error, if any. + #[inline] + pub fn ok(self) -> TreeOption<'a, T> { + unsafe { + TreeOption::new(self.tree, self.owner, self.object.ok()) + } + } + + /// Converts from `TreeResult` to `TreeOption`. + /// + /// Converts `self` into an `TreeOption`, consuming `self`, + /// and discarding the success value, if any. + #[inline] + pub fn err(self) -> TreeOption<'a, String> { + unsafe { + TreeOption::new(self.tree, self.owner, self.object.err()) + } + } + + /// Converts from `&TreeResult` to `TreeResult<&T>`. + /// + /// Produces a new `TreeResult`, containing a reference + /// into the original, leaving the original in place. + #[inline] + pub fn as_ref(&self) -> TreeResult<&T> { + match self.object.as_ref() { + Ok(object) => TreeResult { tree: self.tree, owner: self.owner, object: Ok(object), p_life: self.p_life }, + Err(err) => TreeResult { tree: self.tree, owner: self.owner, object: Err(err.to_string()), p_life: self.p_life } + } + } + + + /// Converts from `&mut TreeResult` to `TreeResult<&mut T>`. + /// + /// Produces a new `TreeResult`, containing a reference + /// into the original, leaving the original in place. + #[inline] + pub fn as_mut(&mut self) -> TreeResult<&mut T> { + match self.object.as_mut() { + Ok(object) => TreeResult { tree: self.tree, owner: self.owner, object: Ok(object), p_life: self.p_life }, + Err(err) => TreeResult { tree: self.tree, owner: self.owner, object: Err(err.to_string()), p_life: self.p_life } + } + } + + // Maps a `TreeResult` to `TreeResult` by applying a function to a + /// contained `Ok` value, leaving an `Err` value untouched. + /// + /// This function can be used to compose the results of two functions. + #[inline] + pub fn map U>(self, op: F) -> TreeResult<'a, U> { + TreeResult { tree: self.tree, owner: self.owner, object: self.object.map(op), p_life: self.p_life } + } + + /// Returns the provided default (if `Err`), or + /// applies a function to the contained value (if `Ok`). + /// + /// Arguments passed to `map_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use `map_or_else`, + /// which is lazily evaluated. + #[inline] + pub fn map_or U>(self, default: U, f: F) -> U { + self.object.map_or(default, f) + } + + /// Maps a `TreeResult` to `U` by applying fallback function `default` to + /// a contained `Err` value, or function `f` to a contained `Ok` value. + /// + /// This function can be used to unpack a successful result + /// while handling an error. + #[inline] + pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { + self.object.map_or_else(default, f) + } + + /// Maps a `TreeResult` to `TreeResult` by applying a function to a + /// contained `Err` value, leaving an `Ok` value untouched. + /// + /// This function can be used to pass through a successful result while handling + /// an error. + #[inline] + pub fn map_err String>(self, op: O) -> TreeResult<'a, T> { + TreeResult { tree: self.tree, owner: self.owner, object: self.object.map_err(op), p_life: self.p_life } + } + + /// Calls a function with a reference to the contained value if `Ok`. + /// + /// Returns the original result. + #[inline] + pub fn inspect(self, f: F) -> Self { + if let Ok(ref t) = self.object { + f(t); + } + self + } + + /// Calls a function with a reference to the contained value if `Err`. + /// + /// Returns the original result. + #[inline] + pub fn inspect_err(self, f: F) -> Self { + if let Err(ref e) = self.object { + f(e); + } + self + } + + /// Converts from `TreeResult` (or `&TreeResult`) to `TreeResult<&::Target>`. + /// + /// Coerces the `Ok` variant of the original `Result` via `Deref` + /// and returns the new `Result`. + #[inline] + pub fn as_deref(&'a self) -> TreeResult<'a, &T::Target> + where + T: Deref, + { self.as_ref().map(|t| t.deref()) } + + /// Converts from `TreeResult` (or `&mut TreeResult`) to `TreeResult<&mut ::Target>`. + /// + /// Coerces the `Ok` variant of the original `Result` via `DerefMut` + /// and returns the new `Result`. + #[inline] + pub fn as_deref_mut(&'a mut self) -> TreeResult<'a, &mut T::Target> + where + T: DerefMut, + { self.as_mut().map(|t| t.deref_mut()) } + + /// Returns an iterator over the possibly contained value. + /// + /// The iterator yields one value if the result is `Result::Ok`, otherwise none. + #[inline] + pub fn iter(&self) -> Iter<'_, T> { + self.object.iter() + } + + /// Returns a mutable iterator over the possibly contained value. + /// + /// The iterator yields one value if the result is `Result::Ok`, otherwise none. + #[inline] + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + self.object.iter_mut() + } + + /// Returns the contained `Ok` value, consuming the `self` value. + /// + /// Because this function may panic, its use is generally discouraged. + /// Instead, prefer to use pattern matching and handle the `Err` + /// case explicitly, or call `unwrap_or`, `unwrap_or_else`, or + /// `unwrap_or_default`. + /// + /// # Panics + /// + /// Panics if the value is an `Err`, with a panic message including the + /// passed message, and the content of the `Err`. + pub fn expect(self, msg: &str) -> T { + match self.object { + Ok(object) => object, + Err(ref err) => self.fail(msg, err) + } + } + + /// Returns the contained `Ok` value, consuming the `self` value. + /// + /// Because this function may panic, its use is generally discouraged. + /// Instead, prefer to use pattern matching and handle the `Err` + /// case explicitly, or call `unwrap_or`, `unwrap_or_else`, or + /// `unwrap_or_default`. + /// + /// # Panics + /// + /// Panics if the value is an `Err`, with a panic message provided by the + /// `Err`'s value. + pub fn unwrap(self) -> T { + match self.object { + Ok(object) => object, + Err(ref err) => self.fail("called `TreeResult::unwrap()` on an `Err` value", err) + } + } + + /// Returns the contained `Ok` value or a default + /// + /// Consumes the `self` argument then, if `Ok`, returns the contained + /// value, otherwise if `Err`, returns the default value for that + /// type. + #[inline] + pub fn unwrap_or_default(self) -> T + where + T: Default, + { + match self.object { + Ok(x) => x, + Err(_) => Default::default(), + } + } + + /// Returns the contained `Err` value, consuming the `self` value. + /// + /// # Panics + /// + /// Panics if the value is an `Ok`, with a panic message including the + /// passed message, and the content of the `Ok`. + #[inline] + pub fn expect_err(self, msg: &str) -> String + where + T: fmt::Debug, + { + match self.object { + Ok(ref t) => self.fail(msg, &format!("{t:?}")), + Err(e) => e + } + } + + /// Returns the contained `Err` value, consuming the `self` value. + /// + /// # Panics + /// + /// Panics if the value is an `Ok`, with a custom panic message provided + /// by the `Ok`'s value. + #[inline] + pub fn unwrap_err(self) -> String + where + T: fmt::Debug, + { + match self.object { + Ok(ref t) => self.fail("called `TreeResult::unwrap_err()` on an `Ok` value", &format!("{t:?}")), + Err(e) => e + } + } + + /// Returns `res` if the result is `Ok`, otherwise returns the `Err` value of `self`. + /// + /// Arguments passed to `and` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use `and_then`, which is + /// lazily evaluated. + #[inline] + pub fn and<'b, U>(self, res: TreeResult<'b, U>) -> TreeResult<'a, U> { + match self.object { + Ok(_) => self.transfer_owner(res), + Err(e) => TreeResult { tree: self.tree, owner: self.owner, object: Err(e), p_life: self.p_life }, + } + } + + /// Calls `op` if the result is `Ok`, otherwise returns the `Err` value of `self`. + /// + /// This function can be used for control flow based on `Result` values. + #[inline] + pub fn and_then TreeResult<'a, U>>(self, op: F) -> TreeResult<'a, U> { + match self.object { + Ok(t) => op(t), + Err(e) => TreeResult { tree: self.tree, owner: self.owner, object: Err(e), p_life: self.p_life } + } + } + + /// Returns `res` if the result is `Err`, otherwise returns the `Ok` value of `self`. + /// + /// Arguments passed to `or` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`or_else`], which is + /// lazily evaluated. + #[inline] + pub fn or<'b>(self, res: TreeResult<'b, T>) -> TreeResult<'a, T> { + match self.object { + Ok(_) => self, + Err(_) => self.transfer_owner(res) + } + } + + /// Calls `op` if the result is `Err`, otherwise returns the `Ok` value of `self`. + /// + /// This function can be used for control flow based on result values. + #[inline] + pub fn or_else<'b, F, O: FnOnce(&str) -> TreeResult<'b, T>>(self, op: O) -> TreeResult<'a, T> { + match self.object { + Ok(_) => self, + Err(ref e) => self.transfer_owner(op(e)) + } + } + + /// Returns the contained `Ok` value or a provided default. + /// + /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use `unwrap_or_else`, + /// which is lazily evaluated. + #[inline] + pub fn unwrap_or(self, default: T) -> T { + match self.object { + Ok(t) => t, + Err(_) => default + } + } + + /// Returns the contained `Ok` value or computes it from a closure. + #[inline] + pub fn unwrap_or_else T>(self, op: F) -> T { + match self.object { + Ok(t) => t, + Err(e) => op(&e), + } + } + + /// Returns the contained `Ok` value, consuming the `self` value, + /// without checking that the value is not an `Err`. + /// + /// # Safety + /// + /// Calling this method on an `Err` is *undefined behavior*. + #[inline] + pub unsafe fn unwrap_unchecked(self) -> T { + match self.object { + Ok(object) => object, + Err(_) => unsafe { unreachable_unchecked() }, + } + } + + /// Returns the contained `Err` value, consuming the `self` value, + /// without checking that the value is not an `Ok`. + /// + /// # Safety + /// + /// Calling this method on an `Ok` is *undefined behavior*. + #[inline] + pub unsafe fn unwrap_err_unchecked(self) -> String { + match self.object { + Ok(_) => unsafe { unreachable_unchecked() }, + Err(err) => err + } + } + + /// Gives another `TreeResult` the same node owner as this one. + pub fn transfer_owner<'b, U>(&self, other: TreeResult<'b, U>) -> TreeResult<'a, U> { + TreeResult { tree: self.tree, owner: self.owner, object: other.object, p_life: self.p_life} + } + + /// Marks a failed operation with a panic on the log, and panics the main thread. + fn fail(&self, msg: &str, error: &str) -> ! { + unsafe { (&mut *self.tree).get_node(self.owner).unwrap_unchecked() }.post(Log::Panic(&format!("{msg}: {error}"))); + println!("\n[RUST TRACE]"); + panic!(); + } +} + +impl <'a, T> TreeResult<'a, &T> { + + /// Maps a `TreeResult<&T>` to a `TreeResult` by copying the contents of the + /// `Ok` part. + #[inline] + pub fn copied(self) -> TreeResult<'a, T> + where + T: Copy, + { self.map(|&t| t) } + + /// Maps a `TreeResult<&T>` to a `TreeResult` by cloning the contents of the + /// `Ok` part. + #[inline] + pub fn cloned(self) -> TreeResult<'a, T> + where + T: Clone, + { self.map(|t| t.clone()) } +} + +impl <'a, T> TreeResult<'a, &mut T> { + + /// Maps a `TreeResult<&mut T>` to a `TreeResult` by copying the contents of the + /// `Ok` part. + #[inline] + pub fn copied(self) -> TreeResult<'a, T> + where + T: Copy, + { self.map(|&mut t| t) } + + /// Maps a `TreeResult<&mut T>` to a `TreeResult` by cloning the contents of the + /// `Ok` part. + #[inline] + pub fn cloned(self) -> TreeResult<'a, T> + where + T: Clone, + { self.map(|t| t.clone()) } +} + +impl <'a, 'b, T> TreeResult<'a, TreeOption<'b, T>> { + + /// Transposes a `TreeResult` of an `TreeOption` into an `TreeOption` of a `TreeResult`. + /// + /// `Ok(None)` will be mapped to `None`. + /// `Ok(Some(_))` and `Err(_)` will be mapped to `Some(Ok(_))` and `Some(Err(_))`. + #[inline] + pub fn transpose(self) -> TreeOption<'a, TreeResult<'a, T>> { + match self.object { + Ok(inner) => { + match inner.to_option() { + Some(x) => unsafe { TreeOption::new(self.tree, self.owner, Some(TreeResult::new(self.tree, self.owner, Ok(x)))) }, + None => unsafe { TreeOption::new(self.tree, self.owner, None) }, + } + }, + Err(e) => unsafe { TreeOption::new(self.tree, self.owner, Some(TreeResult::new(self.tree, self.owner, Err(e)))) } + } + } +} + +impl <'a, 'b, T> TreeResult<'a, TreeResult<'b, T>> { + + /// Converts from `TreeResult>` to `TreeResult` + #[inline] + pub fn flatten(self) -> TreeResult<'a, T> { + match self.object { + Ok(inner) => TreeResult { tree: self.tree, owner: self.owner, object: inner.to_result(), p_life: self.p_life }, + Err(err) => TreeResult { tree: self.tree, owner: self.owner, object: Err(err), p_life: self.p_life } + } + } +} diff --git a/node_tree_core/src/traits/node_getter.rs b/node_tree_core/src/traits/node_getter.rs index f9f8234..b47da0d 100644 --- a/node_tree_core/src/traits/node_getter.rs +++ b/node_tree_core/src/traits/node_getter.rs @@ -23,11 +23,13 @@ //! addresses in the tree. //! +use std::fmt::Debug; + use crate::structs::{ node_tree_base::NodeTreeBase, rid::RID }; /// A trait that is implemented for types that can be used to get node RIDs from the `NodeTree`. -pub trait NodeGetter { +pub trait NodeGetter: Debug { /// A function that must be implemented per compatible type. fn get_from(&self, tree: &NodeTreeBase) -> Option; diff --git a/node_tree_core/tests/error_handling.rs b/node_tree_core/tests/error_handling.rs index b3fab5b..6a5c606 100644 --- a/node_tree_core/tests/error_handling.rs +++ b/node_tree_core/tests/error_handling.rs @@ -29,7 +29,7 @@ impl Node for NodeA { #[test] -#[should_panic] +//#[should_panic] fn test_tree_pointer() { let scene: NodeScene = scene! { NodeA { diff --git a/node_tree_derive/dynamic_logger.png b/node_tree_derive/dynamic_logger.png index 2f1eebb..0f8557c 100644 Binary files a/node_tree_derive/dynamic_logger.png and b/node_tree_derive/dynamic_logger.png differ