1use std::collections::BTreeSet;
4use std::fmt;
5
6use crate::ScopeParseError;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub enum Action {
12 Create,
14 Update,
16 Delete,
18 Manage,
22}
23
24impl Action {
25 fn as_str(self) -> &'static str {
26 match self {
27 Action::Create => "create",
28 Action::Update => "update",
29 Action::Delete => "delete",
30 Action::Manage => "manage",
31 }
32 }
33
34 pub(crate) fn parse(s: &str) -> Result<Self, ScopeParseError> {
35 match s {
36 "create" => Ok(Action::Create),
37 "update" => Ok(Action::Update),
38 "delete" => Ok(Action::Delete),
39 "manage" => Ok(Action::Manage),
40 other => Err(ScopeParseError::UnknownAction(other.to_owned())),
41 }
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
54pub enum ActionSet {
55 All,
57 Only(BTreeSet<Action>),
59}
60
61impl ActionSet {
62 pub(crate) fn contains(&self, other: &ActionSet) -> bool {
63 match (self, other) {
64 (ActionSet::All, _) => true,
65 (ActionSet::Only(_), ActionSet::All) => false,
66 (ActionSet::Only(a), ActionSet::Only(b)) => b.is_subset(a),
67 }
68 }
69
70 pub(crate) fn intersect(&self, other: &ActionSet) -> Option<ActionSet> {
71 match (self, other) {
72 (ActionSet::All, x) | (x, ActionSet::All) => Some(x.clone()),
73 (ActionSet::Only(a), ActionSet::Only(b)) => {
74 let both: BTreeSet<Action> = a.intersection(b).copied().collect();
75 if both.is_empty() {
76 None
77 } else {
78 Some(ActionSet::Only(both))
79 }
80 }
81 }
82 }
83}
84
85impl fmt::Display for ActionSet {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 match self {
88 ActionSet::All => Ok(()),
89 ActionSet::Only(actions) => {
90 let mut sep = '?';
91 for action in actions {
92 write!(f, "{sep}action={}", action.as_str())?;
93 sep = '&';
94 }
95 Ok(())
96 }
97 }
98 }
99}