cedar_policy_core/ast/
literal.rs

1/*
2 * Copyright Cedar Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::ast::{EntityUID, Integer, StaticallyTyped, Type};
18use crate::parser;
19use serde::{Deserialize, Serialize};
20use smol_str::SmolStr;
21use std::sync::Arc;
22
23/// First-class values which may appear as literals in `Expr::Lit`.
24///
25/// Note that the auto-derived `PartialEq` and `Eq` are total equality -- using
26/// == to compare `Literal`s of different types results in `false`, not a type
27/// error.
28///
29/// `Literal` does not include set or record types. Although Cedar has syntax
30/// for set literals (e.g., [2, -7, 8]), these can include arbitrary
31/// expressions (e.g., [2+3, principal.foo]), so they have to become
32/// `Expr::Set`, not `Expr::Lit`.
33///
34/// Cloning is O(1).
35#[derive(Serialize, Deserialize, Hash, Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
36pub enum Literal {
37    /// Boolean value
38    Bool(bool),
39    /// Signed integer value
40    Long(Integer),
41    /// String value
42    String(SmolStr),
43    /// Entity, represented by its UID. To get the actual `Entity`, you have to
44    /// look up this UID in a Store or Slice.
45    EntityUID(Arc<EntityUID>),
46}
47
48impl StaticallyTyped for Literal {
49    fn type_of(&self) -> Type {
50        match self {
51            Self::Bool(_) => Type::Bool,
52            Self::Long(_) => Type::Long,
53            Self::String(_) => Type::String,
54            Self::EntityUID(uid) => uid.type_of(),
55        }
56    }
57}
58
59impl std::fmt::Display for Literal {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        match self {
62            Self::Bool(b) => write!(f, "{}", b),
63            Self::Long(i) => write!(f, "{}", i),
64            // print string literals after the `escape_debug` transformation
65            // note that it adds backslashes for more characters than we may want,
66            // e.g., a single quote is printed as `\'`.
67            Self::String(s) => write!(f, "\"{}\"", s.escape_debug()),
68            Self::EntityUID(uid) => write!(f, "{}", uid),
69        }
70    }
71}
72
73impl std::str::FromStr for Literal {
74    type Err = parser::err::LiteralParseError;
75
76    fn from_str(s: &str) -> Result<Literal, Self::Err> {
77        parser::parse_literal(s)
78    }
79}
80
81/// Create a Literal directly from a bool
82impl From<bool> for Literal {
83    fn from(b: bool) -> Self {
84        Self::Bool(b)
85    }
86}
87
88/// Create a Literal directly from an Integer
89impl From<Integer> for Literal {
90    fn from(i: Integer) -> Self {
91        Self::Long(i)
92    }
93}
94
95/// Create a Literal directly from a String
96impl From<String> for Literal {
97    fn from(s: String) -> Self {
98        Self::String(SmolStr::new(s))
99    }
100}
101
102/// Create a Literal directly from an &str
103impl From<&str> for Literal {
104    fn from(s: &str) -> Self {
105        Self::String(SmolStr::new(s))
106    }
107}
108
109impl From<SmolStr> for Literal {
110    fn from(s: SmolStr) -> Self {
111        Self::String(s)
112    }
113}
114
115/// Create a Literal directly from an EntityUID
116impl From<EntityUID> for Literal {
117    fn from(e: EntityUID) -> Self {
118        Self::EntityUID(Arc::new(e))
119    }
120}
121
122impl From<Arc<EntityUID>> for Literal {
123    fn from(ptr: Arc<EntityUID>) -> Self {
124        Self::EntityUID(ptr)
125    }
126}
127
128impl Literal {
129    /// Check if this literal is an entity reference
130    ///
131    /// This is used for policy scopes, where some syntax is
132    /// required to be an entity reference.
133    pub fn is_ref(&self) -> bool {
134        matches!(self, Self::EntityUID(..))
135    }
136}