didbot_scope/warning.rs
1//! How an atom written in a form the permission spec does not define is
2//! read.
3
4use std::fmt;
5
6/// One way an atom's form departs from the permission spec, and how this
7/// grammar reads it anyway. A spec form carries none.
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub enum ScopeWarning {
10 /// A `repo:` collection or `rpc:` method ending `.*`, such as
11 /// `app.bsky.*`: the NSIDs under that prefix, at any depth.
12 PartialWildcard(String),
13 /// An `rpc:` scope with no `aud`: every audience.
14 NoAudience,
15 /// An `rpc:` scope for every method at every audience: as it is written.
16 EveryMethodAndAudience,
17 /// An `rpc:` `aud` that is neither `*` nor a DID with a service
18 /// fragment: that audience alone, compared as written.
19 NotAServiceReference(String),
20 /// `action=manage` on a `repo:` scope: no record operation, so the
21 /// scope adds no write.
22 RepoManage,
23 /// A comma list of actions, such as `action=create,update`: each action
24 /// in it, as the repeated parameter would name them.
25 ActionList,
26 /// A parameter the scope's kind does not take: ignored.
27 UnknownParameter(String),
28 /// A list parameter written both after the `:` and by name, such as
29 /// `blob:image/png?accept=text/html`: every value.
30 RepeatedList(String),
31 /// A parameter that takes one value given more than once: the first.
32 RepeatedValue(String),
33 /// An atom that names no scope this grammar reads, for the reason given:
34 /// an unknown kind, such as `space:*`, or a value its kind does not
35 /// define, such as `account:status`. It is kept as written, as
36 /// [`crate::Scope::Unknown`], and admits only itself.
37 Unreadable(String),
38}
39
40impl fmt::Display for ScopeWarning {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self {
43 Self::PartialWildcard(pattern) => write!(
44 f,
45 "`{pattern}` is a partial wildcard, read as the NSIDs under that prefix"
46 ),
47 Self::NoAudience => f.write_str("no `aud`, read as every audience"),
48 Self::EveryMethodAndAudience => {
49 f.write_str("every method at every audience, read as written")
50 }
51 Self::NotAServiceReference(aud) => write!(
52 f,
53 "`aud` `{aud}` is not `*` or a DID with a service fragment, read as that \
54 audience alone"
55 ),
56 Self::RepoManage => {
57 f.write_str("`action=manage` names no record operation, so it adds no write")
58 }
59 Self::ActionList => f.write_str("a comma list of actions, read as each action in it"),
60 Self::UnknownParameter(name) => {
61 write!(
62 f,
63 "`{name}` is not a parameter of this kind, and is ignored"
64 )
65 }
66 Self::RepeatedList(name) => write!(
67 f,
68 "`{name}` is written both after the `:` and by name, and every value is read"
69 ),
70 Self::RepeatedValue(name) => {
71 write!(f, "`{name}` is given more than once, and the first is read")
72 }
73 Self::Unreadable(reason) => write!(f, "not a scope this server reads: {reason}"),
74 }
75 }
76}