diff --git a/crates/moongraph/Cargo.toml b/crates/moongraph/Cargo.toml index e0c0325..7eaccfa 100644 --- a/crates/moongraph/Cargo.toml +++ b/crates/moongraph/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moongraph" -version = "0.3.7" +version = "0.3.8" edition = "2021" description = "Schedules and runs DAGs accessing shared resources. 🌙" repository = "https://github.com/schell/moongraph" diff --git a/crates/moongraph/src/lib.rs b/crates/moongraph/src/lib.rs index 0186c9a..9d03576 100644 --- a/crates/moongraph/src/lib.rs +++ b/crates/moongraph/src/lib.rs @@ -421,7 +421,7 @@ impl Gen for NoDefault { /// Immutably borrowed resource that _may_ be created by default. /// -/// [`View`] and [`ViewMut`] are the main way node functions interact with resources. +/// Node functions wrap their parameters in [`View`], [`ViewMut`] or [`Move`]. /// /// `View` has two type parameters: /// * `T` - The type of the resource. @@ -467,7 +467,8 @@ impl> Edges for View { let t = G::generate().context(MissingSnafu { name: std::any::type_name::(), })?; - // UNWRAP: safe because we know this type was missing + // UNWRAP: safe because we know this type was missing, and no other type + // is stored with this type's type id. let _ = resources.insert_value(t).unwrap(); log::trace!("generated missing {}", std::any::type_name::()); // UNWRAP: safe because we just inserted @@ -488,13 +489,33 @@ impl> std::fmt::Display for } } -/// Specifies a graph edge/resource that can be "written" to by a node. -pub struct ViewMut { +/// A mutably borrowed resource that may be created by default. +/// +/// Node functions wrap their parameters in [`View`], [`ViewMut`] or [`Move`]. +/// +/// `ViewMut` has two type parameters: +/// * `T` - The type of the resource. +/// * `G` - The method by which the resource can be generated if it doesn't +/// already exist. By default this is [`SomeDefault`], which denotes creating +/// the resource using its default implementation. Another option is +/// [`NoDefault`] which fails to generate the resource. +/// +/// ```rust +/// use moongraph::*; +/// +/// let mut graph = Graph::default(); +/// let default_number = graph.visit(|u: ViewMut| { *u }).map_err(|e| e.to_string()); +/// assert_eq!(Ok(0), default_number); +/// +/// let no_number = graph.visit(|f: ViewMut| *f); +/// assert!(no_number.is_err()); +/// ``` +pub struct ViewMut = SomeDefault> { inner: LoanMut, - _phantom: PhantomData, + _phantom: PhantomData<(T, G)>, } -impl Deref for ViewMut { +impl> Deref for ViewMut { type Target = T; fn deref(&self) -> &Self::Target { @@ -503,26 +524,34 @@ impl Deref for ViewMut { } } -impl DerefMut for ViewMut { +impl> DerefMut for ViewMut { fn deref_mut(&mut self) -> &mut Self::Target { // UNWRAP: safe because it was constructed with `T` self.inner.downcast_mut().unwrap() } } -impl<'a, T: Any + Send + Sync> Edges for ViewMut { +impl<'a, T: Any + Send + Sync, G: Gen> Edges for ViewMut { fn writes() -> Vec { vec![TypeKey::new::()] } fn construct(resources: &mut TypeMap) -> Result { let key = TypeKey::new::(); - let inner = resources - .loan_mut(key) - .context(ResourceSnafu)? - .context(MissingSnafu { - name: std::any::type_name::(), - })?; + let inner = match resources.loan_mut(key).context(ResourceSnafu)? { + Some(inner) => inner, + None => { + let t = G::generate().context(MissingSnafu { + name: std::any::type_name::(), + })?; + // UNWRAP: safe because we know this type was missing, and no other type + // is stored with this type's type id. + let _ = resources.insert_value(t).unwrap(); + log::trace!("generated missing {}", std::any::type_name::()); + // UNWRAP: safe because we just inserted + resources.loan_mut(key).unwrap().unwrap() + } + }; Ok(ViewMut { inner, _phantom: PhantomData, @@ -530,7 +559,7 @@ impl<'a, T: Any + Send + Sync> Edges for ViewMut { } } -impl std::fmt::Display for ViewMut { +impl> std::fmt::Display for ViewMut { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let t: &T = self.inner.downcast_ref().unwrap(); t.fmt(f) diff --git a/crates/moongraph/src/tutorial_impl.rs b/crates/moongraph/src/tutorial_impl.rs index 8a4dbdd..f891da4 100644 --- a/crates/moongraph/src/tutorial_impl.rs +++ b/crates/moongraph/src/tutorial_impl.rs @@ -204,9 +204,16 @@ /// ```rust /// use moongraph::*; /// +/// #[derive(Default)] /// pub struct Position(f32, f32); +/// +/// #[derive(Default)] /// pub struct Velocity(f32, f32); +/// +/// #[derive(Default)] /// pub struct Acceleration(f32, f32); +/// +/// #[derive(Default)] /// pub struct BankAccount { /// interest_rate: f32, /// balance: f32, @@ -260,6 +267,8 @@ /// /// Notice how the returned schedule shows that `add_velocity` and `compound_interest` can run together in parallel. We call this a "batch". It's possible to run all nodes in a batch at the same time because none of their borrows conflict and there are no explicit ordering constraints between them. /// +/// +/// /// ## Conclusion /// Hopefully by this point you have a better idea what `moongraph` is about and how to use it. /// For more info please look at the module and type level documentation.