spicedb_rust/
entity.rs

1use std::str::FromStr;
2
3use crate::spicedb;
4
5/// An entity is any object in your SpiceDB system
6/// The Id type represents whatever rust type you're using internally, since SpiceDB only uses
7/// Strings to avoid having to convert and deal with errors everywhere we use trait bounds `FromStr` and `Into<String>`
8/// which a lot of common Id types like `Uuid` or `u32` already implement.
9pub trait Entity {
10    type Relations: Relation;
11    type Id: FromStr + Into<String>;
12
13    fn object_type() -> &'static str;
14}
15
16/// Represents possible relations to an `Entity`
17/// Easiest way to implement is implementing `Into<&'static str>` for your enum, which can builder
18/// achieved with `strum::IntoStaticStr`
19pub trait Relation {
20    fn name(self) -> &'static str;
21}
22
23/// A resource is any `Entity` that also has `Permissions` associated
24pub trait Resource: Entity {
25    type Permissions: Permission;
26}
27
28/// Represents possible permissions on a `Resource`
29/// Easiest way to implement is implementing `Into<&'static str>` for your enum, which can builder
30/// achieved with `strum::IntoStaticStr`
31pub trait Permission {
32    fn name(self) -> &'static str;
33}
34
35impl<S> Permission for S
36where
37    S: Into<&'static str>,
38{
39    fn name(self) -> &'static str {
40        self.into()
41    }
42}
43
44impl<S> Relation for S
45where
46    S: Into<&'static str>,
47{
48    fn name(self) -> &'static str {
49        self.into()
50    }
51}
52
53pub trait Caveat {
54    type ContextStruct: Into<prost_types::Struct>;
55    fn name() -> &'static str;
56}
57
58/// Implement the Actor trait for any struct that will represent someone/something taking action in
59/// your system. it could for example be an enum wrapping User/Organization/Service if those are
60/// entities that can take action.
61/// ```rust
62/// pub enum SystemActor {
63///     User(Uuid),
64///     Organization(String),
65///     Service(Uuid),
66/// }
67/// ```
68pub trait Actor {
69    fn to_subject(&self) -> spicedb::SubjectReference;
70}
71
72pub struct NoCaveat;
73
74impl Caveat for NoCaveat {
75    type ContextStruct = prost_types::Struct;
76
77    fn name() -> &'static str {
78        unreachable!()
79    }
80}
81
82/// Use this time for `Relations` when implementing `Entity` for something that will never have a
83/// any relation to.
84pub struct NoRelations;
85
86impl Relation for NoRelations {
87    fn name(self) -> &'static str {
88        unreachable!()
89    }
90}
91
92impl FromStr for NoRelations {
93    type Err = ();
94
95    fn from_str(_: &str) -> Result<Self, Self::Err> {
96        unreachable!()
97    }
98}
99
100/// Use this type to build your wildcard entity types.
101/// Often there already are wildcard shortcuts like `add_wildcard_relationship` in the
102/// `write_relationships_request` builder that can be used instead of this.
103/// However for more niche usecases where you need to pass in a WildCard user for an entity in an
104/// operation that currently doesn't have a shortcut, this can be implemented and used.
105/// ```rust
106/// pub struct WildCardUser;
107///
108/// impl Entity for WildCardUser {
109///     type Id = WildCardId;
110///     type Relations = NoRelations;
111///
112///     fn object_type() -> &'static str {
113///         User::object_type()
114///     }
115/// }
116/// ```
117pub struct WildCardId;
118
119impl FromStr for WildCardId {
120    type Err = ();
121
122    fn from_str(_: &str) -> Result<Self, Self::Err> {
123        unreachable!()
124    }
125}
126
127impl From<WildCardId> for String {
128    fn from(_: WildCardId) -> Self {
129        "*".into()
130    }
131}