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