1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45use crate::error::RoutingError;
6use std::fmt::Debug;
78/// The payload of a walk state.
9pub trait WalkStateUnit<Rhs = Self> {
10type Error: Into<RoutingError>;
1112/// Validates whether the next state in a walk state is valid or not when advancing or
13 /// finalizing.
14fn validate_next(&self, next_state: &Rhs) -> Result<(), Self::Error>;
1516/// The error that is returned by the walk state when attempting to finalize with an invalid
17 /// state.
18fn finalize_error(&self) -> Self::Error;
19}
2021/// WalkState contains all information required to traverse offer and expose chains in a tree
22/// tracing routes from any point back to their originating source. This includes in the most
23/// complex case traversing from a use to offer chain, back through to an expose chain.
24#[derive(Debug, Clone)]
25pub enum WalkState<T: WalkStateUnit + Debug + Clone> {
26 Begin,
27 Intermediate(T),
28 Finished(T),
29}
3031impl<T: WalkStateUnit + Debug + Clone> WalkState<T> {
32/// Constructs a new WalkState representing the start of a walk.
33pub fn new() -> Self {
34 WalkState::Begin
35 }
3637/// Constructs a new WalkState representing the start of a walk after a
38 /// hard coded initial node. Used to represent framework state with static state definitions
39 /// such as rights in directories or filters in events.
40pub fn at(state: T) -> Self {
41 WalkState::Intermediate(state)
42 }
4344/// Advances the WalkState if and only if the state passed satisfies the validation.
45pub fn advance(&self, next_state: Option<T>) -> Result<Self, RoutingError> {
46match (&self, &next_state) {
47 (WalkState::Finished(_), _) => {
48panic!("Attempting to advance a finished WalkState");
49 }
50 (WalkState::Begin, Some(proposed_state)) => {
51Ok(WalkState::Intermediate(proposed_state.clone()))
52 }
53 (WalkState::Intermediate(last_seen_state), Some(proposed_state)) => {
54 last_seen_state.validate_next(proposed_state).map_err(|e| e.into())?;
55Ok(WalkState::Intermediate(proposed_state.clone()))
56 }
57 (_, None) => Ok(self.clone()),
58 }
59 }
6061/// Whether or not the state is Finished.
62pub fn is_finished(&self) -> bool {
63match self {
64 WalkState::Finished(_) => true,
65_ => false,
66 }
67 }
6869/// Finalizes the state preventing future modification, this is called when the walker arrives
70 /// at a node with a source of Framework, Builtin, Namespace or Self. The provided |state|
71 /// should always be the state at the CapabilitySource.
72pub fn finalize(&self, state: Option<T>) -> Result<Self, RoutingError> {
73if self.is_finished() {
74panic!("Attempted to finalized a finished walk state.");
75 }
76if state.is_none() {
77match self {
78 WalkState::Begin => panic!("finalizing a walk state that's only just begun"),
79 WalkState::Intermediate(last_seen_state) => {
80return Err(last_seen_state.finalize_error().into());
81 }
82 WalkState::Finished(_) => {
83unreachable!("Captured earlier");
84 }
85 }
86 }
87let final_state = state.unwrap();
88match self {
89 WalkState::Begin => Ok(WalkState::Finished(final_state)),
90 WalkState::Intermediate(last_seen_state) => {
91 last_seen_state.validate_next(&final_state).map_err(|e| e.into())?;
92Ok(WalkState::Finished(final_state))
93 }
94 WalkState::Finished(_) => {
95unreachable!("Captured earlier");
96 }
97 }
98 }
99}