use crate::{NodeId, RegistrationInfo, RegistrationRule};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StaticFace {
id: NodeId,
parent: NodeId,
owns_registry: bool,
}
impl StaticFace {
pub const fn new(id: NodeId, parent: NodeId, owns_registry: bool) -> Self {
Self {
id,
parent,
owns_registry,
}
}
pub const fn id(self) -> NodeId {
self.id
}
pub const fn parent(self) -> NodeId {
self.parent
}
pub const fn owns_registry(self) -> bool {
self.owns_registry
}
}
#[derive(Clone, Copy, Debug)]
pub struct StaticPlan {
faces: &'static [StaticFace],
grafts: &'static [StaticGraftCut],
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CutTarget {
Path(&'static str),
Id(NodeId),
}
impl CutTarget {
pub const fn id(self) -> Option<NodeId> {
match self {
Self::Id(id) => Some(id),
Self::Path(_) => None,
}
}
pub fn describe(self) -> String {
match self {
Self::Path(path) => path.to_owned(),
Self::Id(id) => id.to_string(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StaticGraftCut {
cut: CutTarget,
cut_end: Option<CutTarget>,
graft: CutTarget,
full: bool,
}
impl StaticGraftCut {
pub const fn new(cut: &'static str, graft: &'static str, full: bool) -> Self {
Self {
cut: CutTarget::Path(cut),
cut_end: None,
graft: CutTarget::Path(graft),
full,
}
}
pub const fn new_range(
start: &'static str,
end: &'static str,
graft: &'static str,
full: bool,
) -> Self {
Self {
cut: CutTarget::Path(start),
cut_end: Some(CutTarget::Path(end)),
graft: CutTarget::Path(graft),
full,
}
}
pub const fn from_ids(cut: NodeId, graft: NodeId, full: bool) -> Self {
Self {
cut: CutTarget::Id(cut),
cut_end: None,
graft: CutTarget::Id(graft),
full,
}
}
pub const fn from_id_range(start: NodeId, end: NodeId, graft: NodeId, full: bool) -> Self {
Self {
cut: CutTarget::Id(start),
cut_end: Some(CutTarget::Id(end)),
graft: CutTarget::Id(graft),
full,
}
}
pub const fn cut(self) -> CutTarget {
self.cut
}
pub const fn cut_end(self) -> Option<CutTarget> {
self.cut_end
}
pub const fn graft(self) -> CutTarget {
self.graft
}
pub const fn full(self) -> bool {
self.full
}
}
impl StaticPlan {
pub const fn with_grafts(
faces: &'static [StaticFace],
grafts: &'static [StaticGraftCut],
) -> Self {
Self { faces, grafts }
}
pub const fn faces(self) -> &'static [StaticFace] {
self.faces
}
pub const fn grafts(self) -> &'static [StaticGraftCut] {
self.grafts
}
pub const fn len(self) -> usize {
self.faces.len()
}
pub const fn is_empty(self) -> bool {
self.faces.is_empty()
}
pub fn find(self, id: NodeId) -> Option<&'static StaticFace> {
self.faces.iter().find(|face| face.id == id)
}
pub fn children_of(self, parent: NodeId) -> impl Iterator<Item = &'static StaticFace> {
self.faces.iter().filter(move |face| face.parent == parent)
}
}
#[doc(hidden)]
pub const fn assert_static_registration(rule: RegistrationRule, info: RegistrationInfo) {
if let Some(required) = rule.required_preset
&& !str_eq(required, info.preset)
{
panic!("static registration failed: wrong preset; see declaration source");
}
if !contains_all(info.contract.provided_parts, rule.required_parts) {
panic!("static registration failed: missing structural part; see declaration source");
}
if !contains_all(info.exports, rule.required_exports) {
panic!("static registration failed: missing export; see declaration source");
}
if !contains_all(info.handle_traits, rule.required_handle_traits) {
panic!("static registration failed: missing handle interface; see declaration source");
}
if !contains_all(info.part_traits, rule.required_part_traits) {
panic!("static registration failed: missing parts interface; see declaration source");
}
if !contains_all(info.contract.provided_parts, info.contract.required_parts) {
panic!(
"static registration failed: preset parts are not satisfied; see declaration source"
);
}
}
const fn contains_all(actual: &[&str], required: &[&str]) -> bool {
let mut index = 0;
while index < required.len() {
if !has_str(actual, required[index]) {
return false;
}
index += 1;
}
true
}
const fn has_str(values: &[&str], needle: &str) -> bool {
let mut index = 0;
while index < values.len() {
if str_eq(values[index], needle) {
return true;
}
index += 1;
}
false
}
const fn str_eq(left: &str, right: &str) -> bool {
let left = left.as_bytes();
let right = right.as_bytes();
if left.len() != right.len() {
return false;
}
let mut index = 0;
while index < left.len() {
if left[index] != right[index] {
return false;
}
index += 1;
}
true
}
#[cfg(test)]
mod static_plan_find_tests {
use super::{NodeId, StaticFace, StaticPlan};
#[test]
fn find_sees_every_face_of_an_unsorted_table() {
static FACES: &[StaticFace] = &[
StaticFace::new(NodeId::from_raw([9; 16]), NodeId::from_raw([0; 16]), true),
StaticFace::new(NodeId::from_raw([1; 16]), NodeId::from_raw([9; 16]), false),
StaticFace::new(NodeId::from_raw([5; 16]), NodeId::from_raw([9; 16]), false),
];
let plan = StaticPlan::with_grafts(FACES, &[]);
for face in FACES {
assert_eq!(plan.find(face.id).map(|found| found.id), Some(face.id));
}
assert!(plan.find(NodeId::from_raw([7; 16])).is_none());
}
}
#[cfg(test)]
mod tests {
use super::*;
const FRAMEWORK: crate::FrameworkId = crate::FrameworkId::new("static-plan-test");
const ROOT: NodeId = crate::root_node_id("static-plan-test");
const CHILD: NodeId = NodeId::from_namespaced_path("static-plan-test", "child.rs", "Child");
static FACES: &[StaticFace] = &[StaticFace::new(CHILD, ROOT, false)];
static GRAFTS: &[StaticGraftCut] = &[StaticGraftCut::new("root/child", "child_fast", false)];
const _: crate::FrameworkId = FRAMEWORK;
const _: &str = stringify!(cut "root/child" graft "child_fast");
#[test]
fn graft_selectors_are_part_of_the_zero_allocation_static_plan() {
let plan = StaticPlan::with_grafts(FACES, GRAFTS);
assert_eq!(plan.len(), 1);
assert_eq!(plan.grafts(), GRAFTS);
}
}