diff --git a/Cargo.lock b/Cargo.lock index 350389d3..82aa3296 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "abscissa" -version = "0.2.1" +version = "0.3.0-rc.0" dependencies = [ "abscissa_core 0.2.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -21,6 +21,7 @@ dependencies = [ "canonical-path 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "generational-arena 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "gumdrop 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", @@ -173,6 +174,14 @@ name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "generational-arena" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "generic-array" version = "0.12.3" @@ -632,6 +641,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum generational-arena 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4024f96ffa0ebaaf36aa589cd41f2fd69f3a5e6fd02c86e11e12cdf41d5b46a3" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum gumdrop 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a57b4113bb9af093a1cd0b505a44a93103e32e258296d01fa2def3f37c2c7cc" "checksum gumdrop_derive 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dae5488e2c090f7586e2027e4ea6fcf8c9d83e2ef64d623993a33a0fb811f1f7" diff --git a/README.md b/README.md index c8e0b2d0..659e1baa 100644 --- a/README.md +++ b/README.md @@ -87,27 +87,28 @@ default set of features in the application: | 6 | [canonical-path] | [iqlusion] | Apache-2.0 | Get canonical fs paths | | 7 | [chrono] | [chronotope] | Apache-2.0/MIT | Time/date library | | 8 | [failure] | [@withoutboats] | Apache-2.0/MIT | Error handling | -| 9 | [gumdrop] | [@Murarth] | Apache-2.0/MIT | Command-line options | -| 10 | [lazy_static] | [rust-lang] | Apache-2.0/MIT | Heap-allocated statics | -| 11 | [libc] | [rust-lang] | Apache-2.0/MIT | C library wrapper | -| 12 | [log] | [rust-lang] | Apache-2.0/MIT | Logging facade library | -| 13 | [num-integer] | [rust-num] | Apache-2.0/MIT | `Integer` trait | -| 14 | [num-traits] | [rust-num] | Apache-2.0/MIT | Numeric traits | -| 15 | [redox_syscall] | [redox-os] | MIT | Redox OS syscall API | -| 16 | [rustc-demangle] | [@alexcrichton] | Apache-2.0/MIT | Symbol demangling | -| 17 | [secrecy] | [iqlusion] | Apache-2.0 | Secret-keeping types | -| 18 | [semver] | [@steveklabnik] | Apache-2.0/MIT | Semantic versioning | -| 19 | [semver-parser] | [@steveklabnik] | Apache-2.0/MIT | Parser for semver spec | -| 20 | [serde] | [serde-rs] | Apache-2.0/MIT | Serialization framework | -| 21 | [signal-hook] | [@vorner] | Apache-2.0/MIT | Unix signal handling | -| 22 | [signal-hook-registry] | [@vorner] | Apache-2.0/MIT | Unix signal registry | -| 23 | [termcolor] | [@BurntSushi] | MIT/Unlicense | Terminal color support | -| 24 | [time] | [rust-lang] | Apache-2.0/MIT | Time/date library | -| 25 | [toml] | [@alexcrichton] | Apache-2.0/MIT | TOML parser library | -| 26 | [winapi]§ | [@retep998] | Apache-2.0/MIT | Windows FFI bindings | -| 27 | [winapi-util] | [@BurntSushi] | MIT/Unlicense | Safe winapi wrappers | -| 28 | [wincolor] | [@BurntSushi] | MIT/Unlicense | Windows console color | -| 29 | [zeroize] | [iqlusion] | Apache-2.0/MIT | Zero out sensitive data | +| 9 | [generational-arena] | [@fitzgen] | MPL-2.0 | Component allocator | +| 10 | [gumdrop] | [@Murarth] | Apache-2.0/MIT | Command-line options | +| 11 | [lazy_static] | [rust-lang] | Apache-2.0/MIT | Heap-allocated statics | +| 12 | [libc] | [rust-lang] | Apache-2.0/MIT | C library wrapper | +| 13 | [log] | [rust-lang] | Apache-2.0/MIT | Logging facade library | +| 14 | [num-integer] | [rust-num] | Apache-2.0/MIT | `Integer` trait | +| 15 | [num-traits] | [rust-num] | Apache-2.0/MIT | Numeric traits | +| 16 | [redox_syscall] | [redox-os] | MIT | Redox OS syscall API | +| 17 | [rustc-demangle] | [@alexcrichton] | Apache-2.0/MIT | Symbol demangling | +| 18 | [secrecy] | [iqlusion] | Apache-2.0 | Secret-keeping types | +| 19 | [semver] | [@steveklabnik] | Apache-2.0/MIT | Semantic versioning | +| 20 | [semver-parser] | [@steveklabnik] | Apache-2.0/MIT | Parser for semver spec | +| 21 | [serde] | [serde-rs] | Apache-2.0/MIT | Serialization framework | +| 22 | [signal-hook] | [@vorner] | Apache-2.0/MIT | Unix signal handling | +| 23 | [signal-hook-registry] | [@vorner] | Apache-2.0/MIT | Unix signal registry | +| 24 | [termcolor] | [@BurntSushi] | MIT/Unlicense | Terminal color support | +| 25 | [time] | [rust-lang] | Apache-2.0/MIT | Time/date library | +| 26 | [toml] | [@alexcrichton] | Apache-2.0/MIT | TOML parser library | +| 27 | [winapi]§ | [@retep998] | Apache-2.0/MIT | Windows FFI bindings | +| 28 | [winapi-util] | [@BurntSushi] | MIT/Unlicense | Safe winapi wrappers | +| 29 | [wincolor] | [@BurntSushi] | MIT/Unlicense | Windows console color | +| 30 | [zeroize] | [iqlusion] | Apache-2.0/MIT | Zero out sensitive data | ### Build / Development / Testing Dependencies @@ -156,6 +157,7 @@ so you only compile the parts you need. | [chrono] | `time` | [abscissa] | | [failure] | - | [abscissa] | | [failure_derive] | - | [failure] | +| [generational-arena] | `application` | [abscissa] | | [gumdrop] | `options` | [abscissa] | | [gumdrop_derive] | `options` | [gumdrop] | | [heck] | `inflector` | [abscissa] | @@ -323,6 +325,7 @@ read the [CONTRIBUTING.md] and [CODE_OF_CONDUCT.md] files first. [chrono]: https://crates.io/crates/chrono [failure]: https://crates.io/crates/failure [failure_derive]: https://crates.io/crates/failure_derive +[generational-arena]: https://github.com/fitzgen/generational-arena [gumdrop]: https://crates.io/crates/gumdrop [gumdrop_derive]: https://crates.io/crates/gumdrop_derive [heck]: https://crates.io/crates/heck @@ -369,6 +372,7 @@ read the [CONTRIBUTING.md] and [CODE_OF_CONDUCT.md] files first. [@BurntSushi]: https://github.com/BurntSushi [@cuviper]: https://github.com/cuviper [@dtolnay]: https://github.com/dtolnay +[@fitzgen]: https://github.com/fitzgen [@Murarth]: https://github.com/Murarth [@mystor]: https://github.com/mystor [@retep998]: https://github.com/retep998 diff --git a/cli/Cargo.toml b/cli/Cargo.toml index f210d197..5fbcbb0f 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -5,7 +5,7 @@ description = """ configuration, error handling, logging, and terminal interactions. This crate contains a CLI utility for generating new applications. """ -version = "0.2.1" # Also update html_root_url in lib.rs when bumping this +version = "0.3.0-rc.0" # Also update html_root_url in lib.rs when bumping this license = "Apache-2.0" authors = ["Tony Arcieri "] edition = "2018" @@ -27,7 +27,7 @@ lazy_static = "1" serde = { version = "1", features = ["serde_derive"] } [dependencies.abscissa_core] -version = "0.2" +version = "0.3.0-rc.0" path = "../core" [dev-dependencies.abscissa_core] diff --git a/cli/src/application.rs b/cli/src/application.rs index 36d61f8c..fd531d02 100644 --- a/cli/src/application.rs +++ b/cli/src/application.rs @@ -53,10 +53,7 @@ impl Application for CliApplication { } fn after_config(&mut self, config: Self::Cfg) -> Result<(), FrameworkError> { - for component in self.state.components.iter_mut() { - component.after_config(&config)?; - } - + self.state.components.after_config(&config)?; self.config = Some(config); Ok(()) } diff --git a/core/Cargo.toml b/core/Cargo.toml index 303f21c9..4022b988 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -5,7 +5,7 @@ description = """ configuration, error handling, logging, and terminal interactions. This crate contains the framework's core functionality. """ -version = "0.2.1" # Also update html_root_url in lib.rs when bumping this +version = "0.3.0-rc.0" # Also update html_root_url in lib.rs when bumping this license = "Apache-2.0" authors = ["Tony Arcieri "] edition = "2018" @@ -16,10 +16,11 @@ categories = ["command-line-interface", "rust-patterns"] keywords = ["abscissa", "cli", "application", "framework", "service"] [dependencies] -abscissa_derive = { version = "0.2", path = "../derive" } +abscissa_derive = { version = "0.3.0-rc.0", path = "../derive" } canonical-path = "2" chrono = { version = "0.4", optional = true, features = ["serde"] } failure = "0.1" +generational-arena = { version = "0.2", optional = true } gumdrop = { version = "0.6", optional = true } lazy_static = "1" log = { version = "0.4", optional = true, features = ["std"] } @@ -36,7 +37,7 @@ libc = { version = "0.2", optional = true } signal-hook = { version = "0.1", optional = true } [features] -default = ["application", "signals", "secrets", "testing", "time"] +default = ["application", "generational-arena", "signals", "secrets", "testing", "time"] application = ["config", "logging", "options", "semver/serde", "terminal"] config = ["secrets", "serde", "terminal", "toml"] logging = ["log"] diff --git a/core/src/component.rs b/core/src/component.rs index 95446564..12ce2894 100644 --- a/core/src/component.rs +++ b/core/src/component.rs @@ -2,10 +2,11 @@ #![allow(unused_variables)] -mod name; +mod handle; +mod id; mod registry; -pub use self::{name::Name, registry::Registry}; +pub use self::{handle::Handle, id::Id, registry::Registry}; use crate::{application::Application, error::FrameworkError, shutdown::Shutdown, Version}; use std::{cmp::Ordering, fmt::Debug, slice::Iter}; @@ -25,14 +26,16 @@ pub trait Component: Debug + Send + Sync where A: Application, { - /// Name of this component - fn name(&self) -> Name; + /// Identifier for this component. + /// + /// These are the Rust path (e.g. `crate_name:foo::Foo`) by convention. + fn id(&self) -> Id; /// Version of this component fn version(&self) -> Version; /// Names of the components this components depends on - fn dependencies(&self) -> Iter<'_, Name> { + fn dependencies(&self) -> Iter<'_, Id> { [].iter() } @@ -42,6 +45,17 @@ where Ok(()) } + /// Register a dependency of this component (a.k.a. "dependency injection") + // TODO(tarcieri): fix clippy warning + #[allow(clippy::borrowed_box)] + fn register_dependency( + &mut self, + handle: Handle, + dependency: &mut Box>, + ) -> Result<(), FrameworkError> { + Ok(()) + } + /// Perform any tasks which should occur before the app exits fn before_shutdown(&self, kind: Shutdown) -> Result<(), FrameworkError> { Ok(()) @@ -53,7 +67,7 @@ where A: Application, { fn eq(&self, other: &Self) -> bool { - self.name() == other.name() + self.id() == other.id() } } @@ -62,13 +76,13 @@ where A: Application, { fn partial_cmp(&self, other: &Self) -> Option { - if other.dependencies().any(|dep| *dep == self.name()) { - if self.dependencies().any(|dep| *dep == other.name()) { + if other.dependencies().any(|dep| *dep == self.id()) { + if self.dependencies().any(|dep| *dep == other.id()) { None } else { Some(Ordering::Greater) } - } else if self.dependencies().any(|dep| *dep == other.name()) { + } else if self.dependencies().any(|dep| *dep == other.id()) { Some(Ordering::Less) } else { Some(Ordering::Equal) diff --git a/core/src/component/handle.rs b/core/src/component/handle.rs new file mode 100644 index 00000000..f105066a --- /dev/null +++ b/core/src/component/handle.rs @@ -0,0 +1,38 @@ +//! Component handles: opaque references to registered components + +use super::id::Id; +use generational_arena::Index; +use std::fmt; + +/// Component handles are references to components which have been registered +/// with a `component::Registry`. +/// +/// However, unlike normal Rust references, component handles are a "weak" +/// reference which is not checked by the borrow checker. This allows for +/// complex reference graphs which are otherwise inexpressible in Rust. +#[derive(Copy, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)] +pub struct Handle { + /// Component name + name: Id, + + /// Index in the registry's generational index allocator + pub(super) index: Index, +} + +impl Handle { + /// Create a new handle from a component's name and index + pub(crate) fn new(name: Id, index: Index) -> Self { + Self { name, index } + } + + /// Get the identifier of the component this handle points to + pub fn id(self) -> Id { + self.name + } +} + +impl fmt::Debug for Handle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Handle({})", self.id().as_ref()) + } +} diff --git a/core/src/component/id.rs b/core/src/component/id.rs new file mode 100644 index 00000000..3aaa0e6b --- /dev/null +++ b/core/src/component/id.rs @@ -0,0 +1,33 @@ +//! Component identifiers +//! +//! By convention these are Rust paths to the component types +// TODO(tarcieri): enforce this convention via e.g. custom derive? + +use std::fmt; + +/// Identifier for an individual component +/// +/// This should ideally match the Rust path name to the corresponding type. +// TODO(tarcieri): obtain this automatically via `std::module_path`? +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)] +pub struct Id(&'static str); + +impl Id { + /// Create a new component identifier + // TODO(tarcieri): make this method private in the future + pub fn new(id: &'static str) -> Id { + Id(id) + } +} + +impl AsRef for Id { + fn as_ref(&self) -> &str { + self.0 + } +} + +impl fmt::Display for Id { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/core/src/component/name.rs b/core/src/component/name.rs deleted file mode 100644 index faaf52ff..00000000 --- a/core/src/component/name.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Component names - -use std::fmt; - -/// Name of an individual component -/// -/// This should ideally match the Rust path name to the corresponding type. -// TODO(tarcieri): obtain this automatically via `std::module_path`? -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)] -pub struct Name(pub &'static str); - -impl AsRef for Name { - fn as_ref(&self) -> &str { - self.0 - } -} - -impl fmt::Display for Name { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} diff --git a/core/src/component/registry.rs b/core/src/component/registry.rs index 762e101b..c4643a81 100644 --- a/core/src/component/registry.rs +++ b/core/src/component/registry.rs @@ -1,12 +1,20 @@ //! Abscissa's component registry -pub use super::Component; +mod iter; + +pub use self::iter::{Iter, IterMut}; + +use super::{handle::Handle, id::Id, Component}; use crate::{ application::{self, Application}, error::{FrameworkError, FrameworkErrorKind::ComponentError}, shutdown::Shutdown, }; -use std::{any::Any, borrow::Borrow, collections::HashSet, slice}; +use generational_arena::{Arena, Index}; +use std::{borrow::Borrow, collections::BTreeMap}; + +/// Index of component identifiers to their arena locations +type IndexMap = BTreeMap; /// The component registry provides a system for runtime registration of /// application components which can interact with each other dynamically. @@ -15,7 +23,11 @@ use std::{any::Any, borrow::Borrow, collections::HashSet, slice}; /// in-order, and at application termination time, shut down in reverse order. #[derive(Debug)] pub struct Registry { - components: Vec>>, + /// Generational arena of registered components + components: Arena>>, + + /// Map of component identifiers to their indexes + index_map: IndexMap, } impl Default for Registry @@ -23,7 +35,10 @@ where A: Application, { fn default() -> Self { - Registry { components: vec![] } + Registry { + components: Arena::new(), + index_map: IndexMap::new(), + } } } @@ -43,23 +58,21 @@ where "no support for registering additional components (yet)" ); - let mut result = Registry { - components: components.into_iter().collect::>(), - }; + let mut components = components.into_iter().collect::>(); - // Ensure all component names are unique - let mut names = HashSet::new(); + components.sort_by(|a, b| { + a.partial_cmp(b) + .unwrap_or_else(|| application::exit::bad_component_order(a.borrow(), b.borrow())) + }); - result.sort(); + for component in components { + let id = component.id(); + let index = self.components.insert(component); - for component in result.components { - ensure!( - names.insert(component.name()), - ComponentError, - "duplicate component name: {}", - component.name() - ); - self.components.push(component); + if self.index_map.insert(id, index).is_some() { + self.components.remove(index); + fail!(ComponentError, "duplicate component ID: {}", id); + } } Ok(()) @@ -67,75 +80,74 @@ where /// Callback fired by application when configuration has been loaded pub fn after_config(&mut self, config: &A::Cfg) -> Result<(), FrameworkError> { - for component in self.iter_mut() { - component.after_config(config)?; + let mut component_indexes: Vec<(Index, Vec)> = vec![]; + + for (index, component) in self.components.iter() { + let mut dep_indexes = vec![]; + + for id in component.dependencies() { + if let Some(index) = self.index_map.get(id) { + dep_indexes.push(*index); + } else { + fail!(ComponentError, "unregistered dependency ID: {}", id); + } + } + + component_indexes.push((index, dep_indexes)); + } + + for (component_index, dep_indexes) in component_indexes { + { + let component = self.components.get_mut(component_index).unwrap(); + component.after_config(config)?; + } + + for dep_index in dep_indexes { + if let (Some(component), Some(dep)) = + self.components.get2_mut(component_index, dep_index) + { + let dep_handle = Handle::new(dep.id(), dep_index); + component.register_dependency(dep_handle, dep)?; + } else { + fail!(ComponentError, "unregistered component dependency"); + } + } } Ok(()) } - /// Iterate over the components. - pub fn iter(&self) -> slice::Iter>> { - self.components.iter() + /// Get a component reference by its handle + pub fn get(&self, handle: Handle) -> Option<&dyn Component> { + self.components.get(handle.index).map(Borrow::borrow) } - /// Iterate over the components mutably. - pub fn iter_mut(&mut self) -> slice::IterMut>> { - self.components.iter_mut() + /// Get a component's handle by its ID + pub fn get_handle_by_id(&self, id: Id) -> Option { + Some(Handle::new(id, *self.index_map.get(&id)?)) } - /// Shutdown components (in the reverse order they were started) - pub fn shutdown(&self, app: &A, shutdown: Shutdown) -> Result<(), FrameworkError> { - for component in self.components.iter().rev() { - component.before_shutdown(shutdown)?; - } - - Ok(()) + /// Get a component ref by its ID + pub fn get_by_id(&self, id: Id) -> Option<&dyn Component> { + self.get(self.get_handle_by_id(id)?) } - /// Sort components by dependency ordering, loading the components that depend - /// on others after their dependencies. - /// - /// Exits the application if the ordering cannot be resolved. - fn sort(&mut self) { - self.components.sort_by(|a, b| { - a.partial_cmp(b) - .unwrap_or_else(|| application::exit::bad_component_order(a.borrow(), b.borrow())) - }) + /// Iterate over the components. + pub fn iter(&self) -> Iter { + Iter::new(self.components.iter()) } -} - -impl Registry -where - A: Application + 'static, -{ - /// Get a reference to a component of the given type, if one has been registered - pub fn get_ref(&self) -> Option<&C> - where - C: Component + 'static, - { - // TODO(tarcieri): more efficient implementation - for component in self.components.iter() { - if let Some(result) = (component as &dyn Any).downcast_ref::() { - return Some(result); - } - } - None + /// Iterate over the components mutably. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.components.iter_mut()) } - /// Get a mutable reference component of the given type, if one has been registered - pub fn get_mut(&mut self) -> Option<&mut C> - where - C: Component + 'static, - { - // TODO(tarcieri): more efficient implementation - for component in self.components.iter_mut() { - if let Some(result) = (component as &mut dyn Any).downcast_mut::() { - return Some(result); - } + /// Shutdown components (in the reverse order they were started) + pub fn shutdown(&self, app: &A, shutdown: Shutdown) -> Result<(), FrameworkError> { + for (_, component) in self.components.iter().rev() { + component.before_shutdown(shutdown)?; } - None + Ok(()) } } diff --git a/core/src/component/registry/iter.rs b/core/src/component/registry/iter.rs new file mode 100644 index 00000000..4f7e473a --- /dev/null +++ b/core/src/component/registry/iter.rs @@ -0,0 +1,64 @@ +//! Iterators over components in the registry + +use crate::{ + application::Application, + component::{Component, Handle}, +}; + +/// Iterator over the components in the arena +pub struct Iter<'a, A: Application> { + iter: generational_arena::Iter<'a, Box>>, +} + +impl<'a, A> Iter<'a, A> +where + A: Application, +{ + /// Create a new iterator + pub(super) fn new(iter: generational_arena::Iter<'a, Box>>) -> Self { + Self { iter } + } +} + +impl<'a, A> Iterator for Iter<'a, A> +where + A: Application, +{ + type Item = (Handle, &'a Box>); + + fn next(&mut self) -> Option { + self.iter.next().map(|(index, component)| { + let handle = Handle::new(component.id(), index); + (handle, component) + }) + } +} + +/// Mutable iterator over the components in the area +pub struct IterMut<'a, A: Application> { + iter_mut: generational_arena::IterMut<'a, Box>>, +} + +impl<'a, A> IterMut<'a, A> +where + A: Application, +{ + /// Create a new mutable iterator + pub(super) fn new(iter_mut: generational_arena::IterMut<'a, Box>>) -> Self { + Self { iter_mut } + } +} + +impl<'a, A> Iterator for IterMut<'a, A> +where + A: Application, +{ + type Item = (Handle, &'a mut Box>); + + fn next(&mut self) -> Option { + self.iter_mut.next().map(|(index, component)| { + let handle = Handle::new(component.id(), index); + (handle, component) + }) + } +} diff --git a/core/src/logging/component.rs b/core/src/logging/component.rs index 9a363476..d56d15a4 100644 --- a/core/src/logging/component.rs +++ b/core/src/logging/component.rs @@ -25,8 +25,8 @@ where A: Application, { /// Name of this component - fn name(&self) -> component::Name { - component::Name("abscissa_core::logging") + fn id(&self) -> component::Id { + component::Id::new("abscissa_core::logging") } /// Version of this component diff --git a/core/src/terminal/component.rs b/core/src/terminal/component.rs index 81b3cdd7..7cf19d32 100644 --- a/core/src/terminal/component.rs +++ b/core/src/terminal/component.rs @@ -22,8 +22,8 @@ where A: Application, { /// Name of this component - fn name(&self) -> component::Name { - component::Name("abscissa_core::terminal") + fn id(&self) -> component::Id { + component::Id::new("abscissa_core::terminal") } /// Version of this component diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 45d64765..bfd3285d 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "abscissa_derive" description = "Custom derive support for the abscissa application microframework" -version = "0.2.1" # Also update html_root_url in lib.rs when bumping this +version = "0.3.0-rc.0" # Also update html_root_url in lib.rs when bumping this license = "Apache-2.0" authors = ["Tony Arcieri "] edition = "2018"