1use super::{
18 err::{JsonDeserializationError, JsonDeserializationErrorContext, JsonSerializationError},
19 SchemaType,
20};
21use crate::entities::{
22 conformance::err::EntitySchemaConformanceError,
23 json::err::{EscapeKind, TypeMismatchError},
24};
25use crate::extensions::Extensions;
26use crate::FromNormalizedStr;
27use crate::{
28 ast::{
29 expression_construction_errors, BorrowedRestrictedExpr, Eid, EntityUID, ExprKind,
30 ExpressionConstructionError, Literal, RestrictedExpr, Unknown, Value, ValueKind,
31 },
32 entities::Name,
33};
34use either::Either;
35use itertools::Itertools;
36use serde::{Deserialize, Serialize};
37use serde_with::serde_as;
38use serde_with::{DeserializeAs, SerializeAs};
39use smol_str::{SmolStr, ToSmolStr};
40use std::collections::{BTreeMap, HashSet};
41use std::sync::Arc;
42
43#[cfg(feature = "wasm")]
44extern crate tsify;
45
46#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
47#[serde(untagged)]
48enum RawCedarValueJson {
49 Bool(bool),
51 Long(i64),
53 String(SmolStr),
55 Set(Vec<RawCedarValueJson>),
58 Record(RawJsonRecord),
61 Null,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
75#[serde(untagged)]
76#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
77#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
78pub enum CedarValueJson {
79 ExprEscape {
81 #[cfg_attr(feature = "wasm", tsify(type = "__skip"))]
83 __expr: SmolStr,
84 },
85 EntityEscape {
94 __entity: TypeAndId,
96 },
97 ExtnEscape {
106 __extn: FnAndArgs,
108 },
109 Bool(bool),
111 Long(i64),
113 String(#[cfg_attr(feature = "wasm", tsify(type = "string"))] SmolStr),
115 Set(Vec<CedarValueJson>),
118 Record(
121 #[cfg_attr(feature = "wasm", tsify(type = "{ [key: string]: CedarValueJson }"))] JsonRecord,
122 ),
123 Null,
126}
127
128impl<'de> Deserialize<'de> for CedarValueJson {
129 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
130 where
131 D: serde::Deserializer<'de>,
132 {
133 let v: RawCedarValueJson = RawCedarValueJson::deserialize(deserializer)?;
134 Ok(v.into())
135 }
136}
137
138impl From<RawCedarValueJson> for CedarValueJson {
139 fn from(value: RawCedarValueJson) -> Self {
140 match value {
141 RawCedarValueJson::Bool(b) => Self::Bool(b),
142 RawCedarValueJson::Long(l) => Self::Long(l),
143 RawCedarValueJson::Null => Self::Null,
144 RawCedarValueJson::Record(r) => {
145 let values = &r.values;
146 if values.len() == 1 {
147 match values.iter().map(|(k, v)| (k.as_str(), v)).collect_vec()[..] {
148 [("__extn", RawCedarValueJson::Record(r))] => {
149 if r.values.len() >= 2 {
150 if let Some(RawCedarValueJson::String(fn_name)) = r.values.get("fn")
151 {
152 if let Some(arg) = r.values.get("arg") {
153 return Self::ExtnEscape {
154 __extn: FnAndArgs::Single {
155 ext_fn: fn_name.clone(),
156 arg: Box::new(arg.clone().into()),
157 },
158 };
159 }
160 if let Some(RawCedarValueJson::Set(args)) = r.values.get("args")
161 {
162 return Self::ExtnEscape {
163 __extn: FnAndArgs::Multi {
164 ext_fn: fn_name.clone(),
165 args: args
166 .iter()
167 .cloned()
168 .map(Into::into)
169 .collect(),
170 },
171 };
172 }
173 }
174 }
175 }
176 [("__expr", RawCedarValueJson::String(s))] => {
177 return Self::ExprEscape { __expr: s.clone() };
178 }
179 [("__entity", RawCedarValueJson::Record(r))] => {
180 if r.values.len() >= 2 {
181 if let Some(RawCedarValueJson::String(ty)) = r.values.get("type") {
182 if let Some(RawCedarValueJson::String(id)) = r.values.get("id")
183 {
184 return Self::EntityEscape {
185 __entity: TypeAndId {
186 entity_type: ty.clone(),
187 id: id.clone(),
188 },
189 };
190 }
191 }
192 }
193 }
194 _ => {}
195 }
196 }
197 Self::Record(r.into())
198 }
199 RawCedarValueJson::Set(s) => Self::Set(s.into_iter().map(Into::into).collect()),
200 RawCedarValueJson::String(s) => Self::String(s),
201 }
202 }
203}
204
205#[serde_as]
206#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
207struct RawJsonRecord {
208 #[serde_as(as = "serde_with::MapPreventDuplicates<_, _>")]
211 #[serde(flatten)]
212 values: BTreeMap<SmolStr, RawCedarValueJson>,
213}
214
215impl From<RawJsonRecord> for JsonRecord {
216 fn from(value: RawJsonRecord) -> Self {
217 JsonRecord {
218 values: value
219 .values
220 .into_iter()
221 .map(|(k, v)| (k, v.into()))
222 .collect(),
223 }
224 }
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
229pub struct JsonRecord {
230 #[serde(flatten)]
233 values: BTreeMap<SmolStr, CedarValueJson>,
234}
235
236impl IntoIterator for JsonRecord {
237 type Item = (SmolStr, CedarValueJson);
238 type IntoIter = <BTreeMap<SmolStr, CedarValueJson> as IntoIterator>::IntoIter;
239 fn into_iter(self) -> Self::IntoIter {
240 self.values.into_iter()
241 }
242}
243
244impl<'a> IntoIterator for &'a JsonRecord {
245 type Item = (&'a SmolStr, &'a CedarValueJson);
246 type IntoIter = <&'a BTreeMap<SmolStr, CedarValueJson> as IntoIterator>::IntoIter;
247 fn into_iter(self) -> Self::IntoIter {
248 self.values.iter()
249 }
250}
251
252impl FromIterator<(SmolStr, CedarValueJson)> for JsonRecord {
259 fn from_iter<T: IntoIterator<Item = (SmolStr, CedarValueJson)>>(iter: T) -> Self {
260 Self {
261 values: BTreeMap::from_iter(iter),
262 }
263 }
264}
265
266impl JsonRecord {
267 pub fn iter(&self) -> impl Iterator<Item = (&'_ SmolStr, &'_ CedarValueJson)> {
269 self.values.iter()
270 }
271
272 pub fn len(&self) -> usize {
274 self.values.len()
275 }
276
277 pub fn is_empty(&self) -> bool {
279 self.values.is_empty()
280 }
281}
282
283#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
285#[serde(rename_all = "camelCase")]
286#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
287#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
288pub struct TypeAndId {
289 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
291 #[serde(rename = "type")]
292 entity_type: SmolStr,
293 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
295 id: SmolStr,
296}
297
298impl From<EntityUID> for TypeAndId {
299 fn from(euid: EntityUID) -> TypeAndId {
300 let (entity_type, eid) = euid.components();
301 TypeAndId {
302 entity_type: entity_type.to_smolstr(),
303 id: AsRef::<str>::as_ref(&eid).into(),
304 }
305 }
306}
307
308impl From<&EntityUID> for TypeAndId {
309 fn from(euid: &EntityUID) -> TypeAndId {
310 TypeAndId {
311 entity_type: euid.entity_type().to_smolstr(),
312 id: AsRef::<str>::as_ref(&euid.eid()).into(),
313 }
314 }
315}
316
317impl TryFrom<TypeAndId> for EntityUID {
318 type Error = crate::parser::err::ParseErrors;
319
320 fn try_from(e: TypeAndId) -> Result<EntityUID, crate::parser::err::ParseErrors> {
321 Ok(EntityUID::from_components(
322 Name::from_normalized_str(&e.entity_type)?.into(),
323 Eid::new(e.id),
324 None,
325 ))
326 }
327}
328
329#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
331#[serde(rename_all = "camelCase")]
332#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
333#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
334#[serde(untagged)]
335pub enum FnAndArgs {
336 Single {
338 #[serde(rename = "fn")]
340 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
341 ext_fn: SmolStr,
342 arg: Box<CedarValueJson>,
344 },
345 Multi {
347 #[serde(rename = "fn")]
349 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
350 ext_fn: SmolStr,
351 args: Vec<CedarValueJson>,
353 },
354}
355
356impl FnAndArgs {
357 pub(crate) fn fn_str(&self) -> &str {
358 match self {
359 Self::Multi { ext_fn, .. } | Self::Single { ext_fn, .. } => ext_fn,
360 }
361 }
362
363 pub(crate) fn args(&self) -> &[CedarValueJson] {
364 match self {
365 Self::Multi { args, .. } => args,
366 Self::Single { arg, .. } => std::slice::from_ref(arg),
367 }
368 }
369}
370
371impl CedarValueJson {
372 pub fn uid(euid: &EntityUID) -> Self {
374 Self::EntityEscape {
375 __entity: TypeAndId::from(euid.clone()),
376 }
377 }
378
379 pub fn into_expr(
381 self,
382 ctx: impl Fn() -> JsonDeserializationErrorContext + Clone,
383 ) -> Result<RestrictedExpr, JsonDeserializationError> {
384 match self {
385 Self::Bool(b) => Ok(RestrictedExpr::val(b)),
386 Self::Long(i) => Ok(RestrictedExpr::val(i)),
387 Self::String(s) => Ok(RestrictedExpr::val(s)),
388 Self::Set(vals) => Ok(RestrictedExpr::set(
389 vals.into_iter()
390 .map(|v| v.into_expr(ctx.clone()))
391 .collect::<Result<Vec<_>, _>>()?,
392 )),
393 Self::Record(map) => Ok(RestrictedExpr::record(
394 map.into_iter()
395 .map(|(k, v)| Ok((k, v.into_expr(ctx.clone())?)))
396 .collect::<Result<Vec<_>, JsonDeserializationError>>()?,
397 )
398 .map_err(|e| match e {
399 ExpressionConstructionError::DuplicateKey(
400 expression_construction_errors::DuplicateKeyError { key, .. },
401 ) => JsonDeserializationError::duplicate_key(ctx(), key),
402 })?),
403 Self::EntityEscape { __entity: entity } => Ok(RestrictedExpr::val(
404 EntityUID::try_from(entity.clone()).map_err(|errs| {
405 let err_msg = serde_json::to_string_pretty(&entity)
406 .unwrap_or_else(|_| format!("{:?}", &entity));
407 JsonDeserializationError::parse_escape(EscapeKind::Entity, err_msg, errs)
408 })?,
409 )),
410 Self::ExtnEscape { __extn: extn } => extn.into_expr(ctx),
411 Self::ExprEscape { .. } => Err(JsonDeserializationError::ExprTag(Box::new(ctx()))),
412 Self::Null => Err(JsonDeserializationError::Null(Box::new(ctx()))),
413 }
414 }
415
416 pub fn from_expr(expr: BorrowedRestrictedExpr<'_>) -> Result<Self, JsonSerializationError> {
418 match expr.as_ref().expr_kind() {
419 ExprKind::Lit(lit) => Ok(Self::from_lit(lit.clone())),
420 ExprKind::ExtensionFunctionApp { fn_name, args } => match args.as_slice() {
421 [] => Err(JsonSerializationError::call_0_args(fn_name.clone())),
422 [arg] => Ok(Self::ExtnEscape {
423 __extn: FnAndArgs::Single {
424 ext_fn: fn_name.to_smolstr(),
425 arg: Box::new(CedarValueJson::from_expr(
426 BorrowedRestrictedExpr::new_unchecked(arg),
428 )?),
429 },
430 }),
431 args => Ok(Self::ExtnEscape {
432 __extn: FnAndArgs::Multi {
433 ext_fn: fn_name.to_smolstr(),
434 args: args
435 .iter()
436 .map(|arg| {
437 CedarValueJson::from_expr(BorrowedRestrictedExpr::new_unchecked(
438 arg,
439 ))
440 })
441 .collect::<Result<Vec<_>, _>>()?,
442 },
443 }),
444 },
445 ExprKind::Set(exprs) => Ok(Self::Set(
446 exprs
447 .iter()
448 .map(BorrowedRestrictedExpr::new_unchecked) .map(CedarValueJson::from_expr)
450 .collect::<Result<_, JsonSerializationError>>()?,
451 )),
452 ExprKind::Record(map) => {
453 check_for_reserved_keys(map.keys())?;
457 Ok(Self::Record(
458 map.iter()
459 .map(|(k, v)| {
460 Ok((
461 k.clone(),
462 CedarValueJson::from_expr(
463 BorrowedRestrictedExpr::new_unchecked(v),
465 )?,
466 ))
467 })
468 .collect::<Result<_, JsonSerializationError>>()?,
469 ))
470 }
471 ExprKind::Unknown(unknown) => Ok(Self::ExtnEscape {
474 __extn: FnAndArgs::Single {
475 ext_fn: "unknown".into(),
476 arg: Box::new(CedarValueJson::String(unknown.name.clone())),
477 },
478 }),
479 kind => Err(JsonSerializationError::unexpected_restricted_expr_kind(
480 kind.clone(),
481 )),
482 }
483 }
484
485 pub fn from_value(value: Value) -> Result<Self, JsonSerializationError> {
496 Self::from_valuekind(value.value)
497 }
498
499 pub fn from_valuekind(value: ValueKind) -> Result<Self, JsonSerializationError> {
503 match value {
504 ValueKind::Lit(lit) => Ok(Self::from_lit(lit)),
505 ValueKind::Set(set) => Ok(Self::Set(
506 set.iter()
507 .cloned()
508 .map(Self::from_value)
509 .collect::<Result<_, _>>()?,
510 )),
511 ValueKind::Record(record) => {
512 check_for_reserved_keys(record.keys())?;
516 Ok(Self::Record(
517 record
518 .iter()
519 .map(|(k, v)| Ok((k.clone(), Self::from_value(v.clone())?)))
520 .collect::<Result<JsonRecord, JsonSerializationError>>()?,
521 ))
522 }
523 ValueKind::ExtensionValue(ev) => {
524 let ext_func = &ev.func;
525 match ev.args.as_slice() {
526 [] => Err(JsonSerializationError::call_0_args(ext_func.clone())),
527 [ref expr] => Ok(Self::ExtnEscape {
528 __extn: FnAndArgs::Single {
529 ext_fn: ext_func.to_smolstr(),
530 arg: Box::new(Self::from_expr(expr.as_borrowed())?),
531 },
532 }),
533 exprs => Ok(Self::ExtnEscape {
534 __extn: FnAndArgs::Multi {
535 ext_fn: ext_func.to_smolstr(),
536 args: exprs
537 .iter()
538 .map(|expr| Self::from_expr(expr.as_borrowed()))
539 .collect::<Result<Vec<_>, _>>()?,
540 },
541 }),
542 }
543 }
544 }
545 }
546
547 pub fn from_lit(lit: Literal) -> Self {
549 match lit {
550 Literal::Bool(b) => Self::Bool(b),
551 Literal::Long(i) => Self::Long(i),
552 Literal::String(s) => Self::String(s),
553 Literal::EntityUID(euid) => Self::EntityEscape {
554 __entity: Arc::unwrap_or_clone(euid).into(),
555 },
556 }
557 }
558
559 pub fn sub_entity_literals(
561 self,
562 mapping: &BTreeMap<EntityUID, EntityUID>,
563 ) -> Result<Self, JsonDeserializationError> {
564 match self {
565 CedarValueJson::ExprEscape { __expr } => Err(JsonDeserializationError::ExprTag(
567 Box::new(JsonDeserializationErrorContext::Unknown),
568 )),
569 CedarValueJson::EntityEscape { __entity } => {
570 let euid = EntityUID::try_from(__entity.clone());
571 match euid {
572 Ok(euid) => match mapping.get(&euid) {
573 Some(new_euid) => Ok(CedarValueJson::EntityEscape {
574 __entity: new_euid.into(),
575 }),
576 None => Ok(CedarValueJson::EntityEscape { __entity }),
577 },
578 Err(_) => Ok(CedarValueJson::EntityEscape { __entity }),
579 }
580 }
581 CedarValueJson::ExtnEscape {
582 __extn: FnAndArgs::Single { ext_fn, arg },
583 } => Ok(CedarValueJson::ExtnEscape {
584 __extn: FnAndArgs::Single {
585 ext_fn,
586 arg: Box::new((*arg).sub_entity_literals(mapping)?),
587 },
588 }),
589 CedarValueJson::ExtnEscape {
590 __extn: FnAndArgs::Multi { ext_fn, args },
591 } => Ok(CedarValueJson::ExtnEscape {
592 __extn: FnAndArgs::Multi {
593 ext_fn,
594 args: args
595 .into_iter()
596 .map(|arg| arg.sub_entity_literals(mapping))
597 .collect::<Result<Vec<_>, _>>()?,
598 },
599 }),
600 v @ CedarValueJson::Bool(_) => Ok(v),
601 v @ CedarValueJson::Long(_) => Ok(v),
602 v @ CedarValueJson::String(_) => Ok(v),
603 CedarValueJson::Set(v) => Ok(CedarValueJson::Set(
604 v.into_iter()
605 .map(|e| e.sub_entity_literals(mapping))
606 .collect::<Result<Vec<_>, _>>()?,
607 )),
608 CedarValueJson::Record(r) => {
609 let mut new_m = BTreeMap::new();
610 for (k, v) in r.values {
611 new_m.insert(k, v.sub_entity_literals(mapping)?);
612 }
613 Ok(CedarValueJson::Record(JsonRecord { values: new_m }))
614 }
615 v @ CedarValueJson::Null => Ok(v),
616 }
617 }
618}
619
620fn check_for_reserved_keys<'a>(
623 mut keys: impl Iterator<Item = &'a SmolStr>,
624) -> Result<(), JsonSerializationError> {
625 let reserved_keys: HashSet<&str> = HashSet::from_iter(["__entity", "__extn", "__expr"]);
630 let collision = keys.find(|k| reserved_keys.contains(k.as_str()));
631 match collision {
632 Some(collision) => Err(JsonSerializationError::reserved_key(collision.clone())),
633 None => Ok(()),
634 }
635}
636
637impl FnAndArgs {
638 pub fn into_expr(
640 self,
641 ctx: impl Fn() -> JsonDeserializationErrorContext + Clone,
642 ) -> Result<RestrictedExpr, JsonDeserializationError> {
643 let ext_fn = self.fn_str();
644 let args = self.args();
645 Ok(RestrictedExpr::call_extension_fn(
646 Name::from_normalized_str(ext_fn).map_err(|errs| {
647 JsonDeserializationError::parse_escape(EscapeKind::Extension, ext_fn, errs)
648 })?,
649 args.iter()
650 .map(|arg| CedarValueJson::into_expr(arg.clone(), ctx.clone()))
651 .collect::<Result<Vec<_>, _>>()?,
652 ))
653 }
654}
655
656#[derive(Debug, Clone)]
658pub struct ValueParser<'e> {
659 extensions: &'e Extensions<'e>,
661}
662
663impl<'e> ValueParser<'e> {
664 pub fn new(extensions: &'e Extensions<'e>) -> Self {
666 Self { extensions }
667 }
668
669 pub fn val_into_restricted_expr(
674 &self,
675 val: serde_json::Value,
676 expected_ty: Option<&SchemaType>,
677 ctx: impl Fn() -> JsonDeserializationErrorContext + Clone,
678 ) -> Result<RestrictedExpr, JsonDeserializationError> {
679 let parse_as_unknown = |val: serde_json::Value| {
682 let extjson: ExtnValueJson = serde_json::from_value(val).ok()?;
683 match extjson {
684 ExtnValueJson::ExplicitExtnEscape {
685 __extn: FnAndArgs::Single { ext_fn, arg },
686 } if ext_fn == "unknown" => {
687 let arg = arg.into_expr(ctx.clone()).ok()?;
688 let name = arg.as_string()?;
689 Some(RestrictedExpr::unknown(Unknown::new_untyped(name.clone())))
690 }
691 _ => None, }
693 };
694 if let Some(rexpr) = parse_as_unknown(val.clone()) {
695 return Ok(rexpr);
696 }
697 match expected_ty {
699 Some(SchemaType::Entity { .. }) => {
704 let uidjson: EntityUidJson = serde_json::from_value(val)?;
705 Ok(RestrictedExpr::val(uidjson.into_euid(ctx)?))
706 }
707 Some(SchemaType::Extension { ref name, .. }) => {
712 let extjson: ExtnValueJson = serde_json::from_value(val)?;
713 match extjson {
714 ExtnValueJson::ExplicitExprEscape { .. } => {
715 Err(JsonDeserializationError::ExprTag(Box::new(ctx())))
716 }
717 ExtnValueJson::ExplicitExtnEscape { __extn }
718 | ExtnValueJson::ImplicitExtnEscape(__extn) => {
719 let func = self.extensions.func(
720 &Name::from_normalized_str(__extn.fn_str()).map_err(|errs| {
721 JsonDeserializationError::parse_escape(
722 EscapeKind::Extension,
723 __extn.fn_str(),
724 errs,
725 )
726 })?,
727 )?;
728 let arg_types = func.arg_types();
729 let args = __extn.args();
730 if args.len() != arg_types.len() {
731 return Err(JsonDeserializationError::incorrect_num_of_arguments(
732 arg_types.len(),
733 args.len(),
734 __extn.fn_str(),
735 ));
736 }
737 Ok(RestrictedExpr::call_extension_fn(
738 func.name().clone(),
739 arg_types
740 .iter()
741 .zip(args.iter())
742 .map(|(arg_type, arg)| {
743 self.val_into_restricted_expr(
749 serde_json::to_value(arg)?,
752 Some(arg_type),
753 ctx.clone(),
754 )
755 })
756 .collect::<Result<Vec<_>, _>>()?,
757 ))
758 }
759 ExtnValueJson::ImplicitConstructor(val) => {
760 let expected_return_type = SchemaType::Extension { name: name.clone() };
761 if let Some(constructor) = self
767 .extensions
768 .lookup_single_arg_constructor(&expected_return_type)
769 {
770 #[allow(clippy::indexing_slicing)]
772 Ok(RestrictedExpr::call_extension_fn(
773 constructor.name().clone(),
774 std::iter::once(self.val_into_restricted_expr(
775 serde_json::to_value(val)?,
776 Some(&constructor.arg_types()[0]),
777 ctx,
778 )?),
779 ))
780 } else {
781 Err(JsonDeserializationError::missing_implied_constructor(
782 ctx(),
783 expected_return_type,
784 ))
785 }
786 }
787 }
788 }
789 Some(expected_ty @ SchemaType::Set { element_ty }) => match val {
792 serde_json::Value::Array(elements) => Ok(RestrictedExpr::set(
793 elements
794 .into_iter()
795 .map(|element| {
796 self.val_into_restricted_expr(element, Some(element_ty), ctx.clone())
797 })
798 .collect::<Result<Vec<RestrictedExpr>, JsonDeserializationError>>()?,
799 )),
800 val => {
801 let actual_val = {
802 let jvalue: CedarValueJson = serde_json::from_value(val)?;
803 jvalue.into_expr(ctx.clone())?
804 };
805 let err = TypeMismatchError::type_mismatch(
806 expected_ty.clone(),
807 actual_val.try_type_of(self.extensions),
808 actual_val,
809 );
810 match ctx() {
811 JsonDeserializationErrorContext::EntityAttribute { uid, attr } => {
812 Err(JsonDeserializationError::EntitySchemaConformance(
813 EntitySchemaConformanceError::type_mismatch(
814 uid,
815 attr,
816 crate::entities::conformance::err::AttrOrTag::Attr,
817 err,
818 ),
819 ))
820 }
821 ctx => Err(JsonDeserializationError::type_mismatch(ctx, err)),
822 }
823 }
824 },
825 Some(
829 expected_ty @ SchemaType::Record {
830 attrs: expected_attrs,
831 open_attrs,
832 },
833 ) => match val {
834 serde_json::Value::Object(mut actual_attrs) => {
835 let ctx2 = ctx.clone(); let mut_actual_attrs = &mut actual_attrs; let rexpr_pairs = expected_attrs
838 .iter()
839 .filter_map(move |(k, expected_attr_ty)| {
840 match mut_actual_attrs.remove(k.as_str()) {
841 Some(actual_attr) => {
842 match self.val_into_restricted_expr(actual_attr, Some(expected_attr_ty.schema_type()), ctx.clone()) {
843 Ok(actual_attr) => Some(Ok((k.clone(), actual_attr))),
844 Err(e) => Some(Err(e)),
845 }
846 }
847 None if expected_attr_ty.is_required() => Some(Err(JsonDeserializationError::missing_required_record_attr(ctx(), k.clone()))),
848 None => None,
849 }
850 })
851 .collect::<Result<Vec<(SmolStr, RestrictedExpr)>, JsonDeserializationError>>()?;
852
853 if !open_attrs {
854 if let Some((record_attr, _)) = actual_attrs.into_iter().next() {
857 return Err(JsonDeserializationError::unexpected_record_attr(
858 ctx2(),
859 record_attr,
860 ));
861 }
862 }
863
864 RestrictedExpr::record(rexpr_pairs).map_err(|e| match e {
869 ExpressionConstructionError::DuplicateKey(
870 expression_construction_errors::DuplicateKeyError { key, .. },
871 ) => JsonDeserializationError::duplicate_key(ctx2(), key),
872 })
873 }
874 val => {
875 let actual_val = {
876 let jvalue: CedarValueJson = serde_json::from_value(val)?;
877 jvalue.into_expr(ctx.clone())?
878 };
879 let err = TypeMismatchError::type_mismatch(
880 expected_ty.clone(),
881 actual_val.try_type_of(self.extensions),
882 actual_val,
883 );
884 match ctx() {
885 JsonDeserializationErrorContext::EntityAttribute { uid, attr } => {
886 Err(JsonDeserializationError::EntitySchemaConformance(
887 EntitySchemaConformanceError::type_mismatch(
888 uid,
889 attr,
890 crate::entities::conformance::err::AttrOrTag::Attr,
891 err,
892 ),
893 ))
894 }
895 ctx => Err(JsonDeserializationError::type_mismatch(ctx, err)),
896 }
897 }
898 },
899 Some(_) | None => {
902 let jvalue: CedarValueJson = serde_json::from_value(val)?;
905 Ok(jvalue.into_expr(ctx)?)
906 }
907 }
908 }
909}
910
911pub trait DeserializationContext {
915 fn static_context() -> Option<JsonDeserializationErrorContext>;
918}
919
920#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
923pub struct NoStaticContext;
924
925impl DeserializationContext for NoStaticContext {
926 fn static_context() -> Option<JsonDeserializationErrorContext> {
927 None
928 }
929}
930
931#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
934#[serde(untagged)]
935#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
936#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
937pub enum EntityUidJson<Context = NoStaticContext> {
938 ExplicitExprEscape {
940 #[cfg_attr(feature = "wasm", tsify(type = "__skip"))]
942 __expr: String,
943 #[serde(skip)]
945 context: std::marker::PhantomData<Context>,
946 },
947 ExplicitEntityEscape {
949 __entity: TypeAndId,
951 },
952 ImplicitEntityEscape(TypeAndId),
955
956 FoundValue(#[cfg_attr(feature = "wasm", tsify(type = "__skip"))] serde_json::Value),
958}
959
960impl<'de, C: DeserializationContext> DeserializeAs<'de, EntityUID> for EntityUidJson<C> {
961 fn deserialize_as<D>(deserializer: D) -> Result<EntityUID, D::Error>
962 where
963 D: serde::Deserializer<'de>,
964 {
965 use serde::de::Error;
966 let context = || JsonDeserializationErrorContext::Unknown;
968 let s = EntityUidJson::<C>::deserialize(deserializer)?;
969 let euid = s.into_euid(context).map_err(Error::custom)?;
970 Ok(euid)
971 }
972}
973
974impl<C> SerializeAs<EntityUID> for EntityUidJson<C> {
975 fn serialize_as<S>(source: &EntityUID, serializer: S) -> Result<S::Ok, S::Error>
976 where
977 S: serde::Serializer,
978 {
979 let json: EntityUidJson = source.clone().into();
980 json.serialize(serializer)
981 }
982}
983
984impl<C: DeserializationContext> EntityUidJson<C> {
985 pub fn new(entity_type: impl Into<SmolStr>, id: impl Into<SmolStr>) -> Self {
989 Self::ImplicitEntityEscape(TypeAndId {
990 entity_type: entity_type.into(),
991 id: id.into(),
992 })
993 }
994
995 pub fn into_euid(
997 self,
998 dynamic_ctx: impl Fn() -> JsonDeserializationErrorContext + Clone,
999 ) -> Result<EntityUID, JsonDeserializationError> {
1000 let ctx = || C::static_context().unwrap_or_else(&dynamic_ctx);
1001 match self {
1002 Self::ExplicitEntityEscape { __entity } | Self::ImplicitEntityEscape(__entity) => {
1003 let jvalue = CedarValueJson::EntityEscape { __entity };
1005 let expr = jvalue.into_expr(ctx)?;
1006 match expr.expr_kind() {
1007 ExprKind::Lit(Literal::EntityUID(euid)) => Ok((**euid).clone()),
1008 _ => Err(JsonDeserializationError::expected_entity_ref(
1009 ctx(),
1010 Either::Right(expr.clone().into()),
1011 )),
1012 }
1013 }
1014 Self::FoundValue(v) => Err(JsonDeserializationError::expected_entity_ref(
1015 ctx(),
1016 Either::Left(v),
1017 )),
1018 Self::ExplicitExprEscape { __expr, .. } => {
1019 Err(JsonDeserializationError::ExprTag(Box::new(ctx())))
1020 }
1021 }
1022 }
1023}
1024
1025impl From<EntityUID> for EntityUidJson {
1027 fn from(uid: EntityUID) -> EntityUidJson {
1028 EntityUidJson::ExplicitEntityEscape {
1029 __entity: uid.into(),
1030 }
1031 }
1032}
1033
1034impl From<&EntityUID> for EntityUidJson {
1036 fn from(uid: &EntityUID) -> EntityUidJson {
1037 EntityUidJson::ExplicitEntityEscape {
1038 __entity: uid.into(),
1039 }
1040 }
1041}
1042
1043#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1046#[serde(untagged)]
1047pub enum ExtnValueJson {
1048 ExplicitExprEscape {
1050 __expr: String,
1052 },
1053 ExplicitExtnEscape {
1055 __extn: FnAndArgs,
1057 },
1058 ImplicitExtnEscape(FnAndArgs),
1061 ImplicitConstructor(CedarValueJson),
1067}