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 serde::{Deserialize, Serialize};
36use serde_with::serde_as;
37use serde_with::{DeserializeAs, SerializeAs};
38use smol_str::SmolStr;
39use std::collections::{BTreeMap, HashSet};
40use std::sync::Arc;
41
42#[cfg(feature = "wasm")]
43extern crate tsify;
44
45#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
54#[serde(untagged)]
55#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
56#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
57pub enum CedarValueJson {
58 ExprEscape {
60 #[cfg_attr(feature = "wasm", tsify(type = "__skip"))]
62 __expr: SmolStr,
63 },
64 EntityEscape {
73 __entity: TypeAndId,
75 },
76 ExtnEscape {
85 __extn: FnAndArg,
87 },
88 Bool(bool),
90 Long(i64),
92 String(#[cfg_attr(feature = "wasm", tsify(type = "string"))] SmolStr),
94 Set(Vec<CedarValueJson>),
97 Record(
100 #[cfg_attr(feature = "wasm", tsify(type = "{ [key: string]: CedarValueJson }"))] JsonRecord,
101 ),
102 Null,
105}
106
107#[serde_as]
109#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
110pub struct JsonRecord {
111 #[serde_as(as = "serde_with::MapPreventDuplicates<_, _>")]
114 #[serde(flatten)]
115 values: BTreeMap<SmolStr, CedarValueJson>,
116}
117
118impl IntoIterator for JsonRecord {
119 type Item = (SmolStr, CedarValueJson);
120 type IntoIter = <BTreeMap<SmolStr, CedarValueJson> as IntoIterator>::IntoIter;
121 fn into_iter(self) -> Self::IntoIter {
122 self.values.into_iter()
123 }
124}
125
126impl<'a> IntoIterator for &'a JsonRecord {
127 type Item = (&'a SmolStr, &'a CedarValueJson);
128 type IntoIter = <&'a BTreeMap<SmolStr, CedarValueJson> as IntoIterator>::IntoIter;
129 fn into_iter(self) -> Self::IntoIter {
130 self.values.iter()
131 }
132}
133
134impl FromIterator<(SmolStr, CedarValueJson)> for JsonRecord {
141 fn from_iter<T: IntoIterator<Item = (SmolStr, CedarValueJson)>>(iter: T) -> Self {
142 Self {
143 values: BTreeMap::from_iter(iter),
144 }
145 }
146}
147
148impl JsonRecord {
149 pub fn iter(&self) -> impl Iterator<Item = (&'_ SmolStr, &'_ CedarValueJson)> {
151 self.values.iter()
152 }
153
154 pub fn len(&self) -> usize {
156 self.values.len()
157 }
158
159 pub fn is_empty(&self) -> bool {
161 self.values.is_empty()
162 }
163}
164
165#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
167#[serde(rename_all = "camelCase")]
168#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
169#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
170pub struct TypeAndId {
171 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
173 #[serde(rename = "type")]
174 entity_type: SmolStr,
175 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
177 id: SmolStr,
178}
179
180impl From<EntityUID> for TypeAndId {
181 fn from(euid: EntityUID) -> TypeAndId {
182 let (entity_type, eid) = euid.components();
183 TypeAndId {
184 entity_type: entity_type.to_string().into(),
185 id: AsRef::<str>::as_ref(&eid).into(),
186 }
187 }
188}
189
190impl From<&EntityUID> for TypeAndId {
191 fn from(euid: &EntityUID) -> TypeAndId {
192 TypeAndId {
193 entity_type: euid.entity_type().to_string().into(),
194 id: AsRef::<str>::as_ref(&euid.eid()).into(),
195 }
196 }
197}
198
199impl TryFrom<TypeAndId> for EntityUID {
200 type Error = crate::parser::err::ParseErrors;
201
202 fn try_from(e: TypeAndId) -> Result<EntityUID, Self::Error> {
203 Ok(EntityUID::from_components(
204 Name::from_normalized_str(&e.entity_type)?.into(),
205 Eid::new(e.id),
206 None,
207 ))
208 }
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
213#[serde(rename_all = "camelCase")]
214#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
215#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
216pub struct FnAndArg {
217 #[serde(rename = "fn")]
219 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
220 pub(crate) ext_fn: SmolStr,
221 pub(crate) arg: Box<CedarValueJson>,
223}
224
225impl CedarValueJson {
226 pub fn uid(euid: &EntityUID) -> Self {
228 Self::EntityEscape {
229 __entity: TypeAndId::from(euid.clone()),
230 }
231 }
232
233 pub fn into_expr(
235 self,
236 ctx: impl Fn() -> JsonDeserializationErrorContext + Clone,
237 ) -> Result<RestrictedExpr, JsonDeserializationError> {
238 match self {
239 Self::Bool(b) => Ok(RestrictedExpr::val(b)),
240 Self::Long(i) => Ok(RestrictedExpr::val(i)),
241 Self::String(s) => Ok(RestrictedExpr::val(s)),
242 Self::Set(vals) => Ok(RestrictedExpr::set(
243 vals.into_iter()
244 .map(|v| v.into_expr(ctx.clone()))
245 .collect::<Result<Vec<_>, _>>()?,
246 )),
247 Self::Record(map) => Ok(RestrictedExpr::record(
248 map.into_iter()
249 .map(|(k, v)| Ok((k, v.into_expr(ctx.clone())?)))
250 .collect::<Result<Vec<_>, JsonDeserializationError>>()?,
251 )
252 .map_err(|e| match e {
253 ExpressionConstructionError::DuplicateKey(
254 expression_construction_errors::DuplicateKeyError { key, .. },
255 ) => JsonDeserializationError::duplicate_key(ctx(), key),
256 })?),
257 Self::EntityEscape { __entity: entity } => Ok(RestrictedExpr::val(
258 EntityUID::try_from(entity.clone()).map_err(|errs| {
259 let err_msg = serde_json::to_string_pretty(&entity)
260 .unwrap_or_else(|_| format!("{:?}", &entity));
261 JsonDeserializationError::parse_escape(EscapeKind::Entity, err_msg, errs)
262 })?,
263 )),
264 Self::ExtnEscape { __extn: extn } => extn.into_expr(ctx),
265 Self::ExprEscape { .. } => Err(JsonDeserializationError::ExprTag(Box::new(ctx()))),
266 Self::Null => Err(JsonDeserializationError::Null(Box::new(ctx()))),
267 }
268 }
269
270 pub fn from_expr(expr: BorrowedRestrictedExpr<'_>) -> Result<Self, JsonSerializationError> {
272 match expr.as_ref().expr_kind() {
273 ExprKind::Lit(lit) => Ok(Self::from_lit(lit.clone())),
274 ExprKind::ExtensionFunctionApp { fn_name, args } => match args.len() {
275 0 => Err(JsonSerializationError::call_0_args(fn_name.clone())),
276 #[allow(clippy::indexing_slicing)]
278 1 => Ok(Self::ExtnEscape {
279 __extn: FnAndArg {
280 ext_fn: fn_name.to_string().into(),
281 arg: Box::new(CedarValueJson::from_expr(
282 BorrowedRestrictedExpr::new_unchecked(
284 &args[0], ),
286 )?),
287 },
288 }),
289 _ => Err(JsonSerializationError::call_2_or_more_args(fn_name.clone())),
290 },
291 ExprKind::Set(exprs) => Ok(Self::Set(
292 exprs
293 .iter()
294 .map(BorrowedRestrictedExpr::new_unchecked) .map(CedarValueJson::from_expr)
296 .collect::<Result<_, JsonSerializationError>>()?,
297 )),
298 ExprKind::Record(map) => {
299 check_for_reserved_keys(map.keys())?;
303 Ok(Self::Record(
304 map.iter()
305 .map(|(k, v)| {
306 Ok((
307 k.clone(),
308 CedarValueJson::from_expr(
309 BorrowedRestrictedExpr::new_unchecked(v),
311 )?,
312 ))
313 })
314 .collect::<Result<_, JsonSerializationError>>()?,
315 ))
316 }
317 kind => Err(JsonSerializationError::unexpected_restricted_expr_kind(
318 kind.clone(),
319 )),
320 }
321 }
322
323 pub fn from_value(value: Value) -> Result<Self, JsonSerializationError> {
334 Self::from_valuekind(value.value)
335 }
336
337 pub fn from_valuekind(value: ValueKind) -> Result<Self, JsonSerializationError> {
341 match value {
342 ValueKind::Lit(lit) => Ok(Self::from_lit(lit)),
343 ValueKind::Set(set) => Ok(Self::Set(
344 set.iter()
345 .cloned()
346 .map(Self::from_value)
347 .collect::<Result<_, _>>()?,
348 )),
349 ValueKind::Record(record) => {
350 check_for_reserved_keys(record.keys())?;
354 Ok(Self::Record(
355 record
356 .iter()
357 .map(|(k, v)| Ok((k.clone(), Self::from_value(v.clone())?)))
358 .collect::<Result<JsonRecord, JsonSerializationError>>()?,
359 ))
360 }
361 ValueKind::ExtensionValue(ev) => {
362 let ext_fn: &Name = &ev.constructor;
363 Ok(Self::ExtnEscape {
364 __extn: FnAndArg {
365 ext_fn: ext_fn.to_string().into(),
366 arg: match ev.args.as_slice() {
367 [ref expr] => Box::new(Self::from_expr(expr.as_borrowed())?),
368 [] => return Err(JsonSerializationError::call_0_args(ext_fn.clone())),
369 _ => {
370 return Err(JsonSerializationError::call_2_or_more_args(
371 ext_fn.clone(),
372 ))
373 }
374 },
375 },
376 })
377 }
378 }
379 }
380
381 pub fn from_lit(lit: Literal) -> Self {
383 match lit {
384 Literal::Bool(b) => Self::Bool(b),
385 Literal::Long(i) => Self::Long(i),
386 Literal::String(s) => Self::String(s),
387 Literal::EntityUID(euid) => Self::EntityEscape {
388 __entity: Arc::unwrap_or_clone(euid).into(),
389 },
390 }
391 }
392
393 pub fn sub_entity_literals(
395 self,
396 mapping: &BTreeMap<EntityUID, EntityUID>,
397 ) -> Result<Self, JsonDeserializationError> {
398 match self.clone() {
399 CedarValueJson::ExprEscape { __expr } => Err(JsonDeserializationError::ExprTag(
401 Box::new(JsonDeserializationErrorContext::Unknown),
402 )),
403 CedarValueJson::EntityEscape { __entity } => {
404 let euid = EntityUID::try_from(__entity);
405 match euid {
406 Ok(euid) => match mapping.get(&euid) {
407 Some(new_euid) => Ok(CedarValueJson::EntityEscape {
408 __entity: new_euid.into(),
409 }),
410 None => Ok(self.clone()),
411 },
412 Err(_) => Ok(self.clone()),
413 }
414 }
415 CedarValueJson::ExtnEscape { __extn } => Ok(CedarValueJson::ExtnEscape {
416 __extn: FnAndArg {
417 ext_fn: __extn.ext_fn,
418 arg: Box::new((*__extn.arg).sub_entity_literals(mapping)?),
419 },
420 }),
421 CedarValueJson::Bool(_) => Ok(self.clone()),
422 CedarValueJson::Long(_) => Ok(self.clone()),
423 CedarValueJson::String(_) => Ok(self.clone()),
424 CedarValueJson::Set(v) => Ok(CedarValueJson::Set(
425 v.into_iter()
426 .map(|e| e.sub_entity_literals(mapping))
427 .collect::<Result<Vec<_>, _>>()?,
428 )),
429 CedarValueJson::Record(r) => {
430 let mut new_m = BTreeMap::new();
431 for (k, v) in r.values {
432 new_m.insert(k, v.sub_entity_literals(mapping)?);
433 }
434 Ok(CedarValueJson::Record(JsonRecord { values: new_m }))
435 }
436 CedarValueJson::Null => Ok(self.clone()),
437 }
438 }
439}
440
441fn check_for_reserved_keys<'a>(
444 mut keys: impl Iterator<Item = &'a SmolStr>,
445) -> Result<(), JsonSerializationError> {
446 let reserved_keys: HashSet<&str> = HashSet::from_iter(["__entity", "__extn", "__expr"]);
451 let collision = keys.find(|k| reserved_keys.contains(k.as_str()));
452 match collision {
453 Some(collision) => Err(JsonSerializationError::reserved_key(collision.clone())),
454 None => Ok(()),
455 }
456}
457
458impl FnAndArg {
459 pub fn into_expr(
461 self,
462 ctx: impl Fn() -> JsonDeserializationErrorContext + Clone,
463 ) -> Result<RestrictedExpr, JsonDeserializationError> {
464 Ok(RestrictedExpr::call_extension_fn(
465 Name::from_normalized_str(&self.ext_fn).map_err(|errs| {
466 JsonDeserializationError::parse_escape(EscapeKind::Extension, self.ext_fn, errs)
467 })?,
468 vec![CedarValueJson::into_expr(*self.arg, ctx)?],
469 ))
470 }
471}
472
473#[derive(Debug, Clone)]
475pub struct ValueParser<'e> {
476 extensions: &'e Extensions<'e>,
478}
479
480impl<'e> ValueParser<'e> {
481 pub fn new(extensions: &'e Extensions<'e>) -> Self {
483 Self { extensions }
484 }
485
486 pub fn val_into_restricted_expr(
491 &self,
492 val: serde_json::Value,
493 expected_ty: Option<&SchemaType>,
494 ctx: impl Fn() -> JsonDeserializationErrorContext + Clone,
495 ) -> Result<RestrictedExpr, JsonDeserializationError> {
496 let parse_as_unknown = |val: serde_json::Value| {
499 let extjson: ExtnValueJson = serde_json::from_value(val).ok()?;
500 match extjson {
501 ExtnValueJson::ExplicitExtnEscape {
502 __extn: FnAndArg { ext_fn, arg },
503 } if ext_fn == "unknown" => {
504 let arg = arg.into_expr(ctx.clone()).ok()?;
505 let name = arg.as_string()?;
506 Some(RestrictedExpr::unknown(Unknown::new_untyped(name.clone())))
507 }
508 _ => None, }
510 };
511 if let Some(rexpr) = parse_as_unknown(val.clone()) {
512 return Ok(rexpr);
513 }
514 match expected_ty {
516 Some(SchemaType::Entity { .. }) => {
521 let uidjson: EntityUidJson = serde_json::from_value(val)?;
522 Ok(RestrictedExpr::val(uidjson.into_euid(ctx)?))
523 }
524 Some(SchemaType::Extension { ref name, .. }) => {
529 let extjson: ExtnValueJson = serde_json::from_value(val)?;
530 self.extn_value_json_into_rexpr(extjson, name.clone(), ctx)
531 }
532 Some(expected_ty @ SchemaType::Set { element_ty }) => match val {
535 serde_json::Value::Array(elements) => Ok(RestrictedExpr::set(
536 elements
537 .into_iter()
538 .map(|element| {
539 self.val_into_restricted_expr(element, Some(element_ty), ctx.clone())
540 })
541 .collect::<Result<Vec<RestrictedExpr>, JsonDeserializationError>>()?,
542 )),
543 val => {
544 let actual_val = {
545 let jvalue: CedarValueJson = serde_json::from_value(val)?;
546 jvalue.into_expr(ctx.clone())?
547 };
548 let err = TypeMismatchError::type_mismatch(
549 expected_ty.clone(),
550 actual_val.try_type_of(self.extensions),
551 actual_val,
552 );
553 match ctx() {
554 JsonDeserializationErrorContext::EntityAttribute { uid, attr } => {
555 Err(JsonDeserializationError::EntitySchemaConformance(
556 EntitySchemaConformanceError::type_mismatch(uid, attr, err),
557 ))
558 }
559 ctx => Err(JsonDeserializationError::type_mismatch(ctx, err)),
560 }
561 }
562 },
563 Some(
567 expected_ty @ SchemaType::Record {
568 attrs: expected_attrs,
569 open_attrs,
570 },
571 ) => match val {
572 serde_json::Value::Object(mut actual_attrs) => {
573 let ctx2 = ctx.clone(); let mut_actual_attrs = &mut actual_attrs; let rexpr_pairs = expected_attrs
576 .iter()
577 .filter_map(move |(k, expected_attr_ty)| {
578 match mut_actual_attrs.remove(k.as_str()) {
579 Some(actual_attr) => {
580 match self.val_into_restricted_expr(actual_attr, Some(expected_attr_ty.schema_type()), ctx.clone()) {
581 Ok(actual_attr) => Some(Ok((k.clone(), actual_attr))),
582 Err(e) => Some(Err(e)),
583 }
584 }
585 None if expected_attr_ty.is_required() => Some(Err(JsonDeserializationError::missing_required_record_attr(ctx(), k.clone()))),
586 None => None,
587 }
588 })
589 .collect::<Result<Vec<(SmolStr, RestrictedExpr)>, JsonDeserializationError>>()?;
590
591 if !open_attrs {
592 if let Some((record_attr, _)) = actual_attrs.into_iter().next() {
595 return Err(JsonDeserializationError::unexpected_record_attr(
596 ctx2(),
597 record_attr,
598 ));
599 }
600 }
601
602 RestrictedExpr::record(rexpr_pairs).map_err(|e| match e {
607 ExpressionConstructionError::DuplicateKey(
608 expression_construction_errors::DuplicateKeyError { key, .. },
609 ) => JsonDeserializationError::duplicate_key(ctx2(), key),
610 })
611 }
612 val => {
613 let actual_val = {
614 let jvalue: CedarValueJson = serde_json::from_value(val)?;
615 jvalue.into_expr(ctx.clone())?
616 };
617 let err = TypeMismatchError::type_mismatch(
618 expected_ty.clone(),
619 actual_val.try_type_of(self.extensions),
620 actual_val,
621 );
622 match ctx() {
623 JsonDeserializationErrorContext::EntityAttribute { uid, attr } => {
624 Err(JsonDeserializationError::EntitySchemaConformance(
625 EntitySchemaConformanceError::type_mismatch(uid, attr, err),
626 ))
627 }
628 ctx => Err(JsonDeserializationError::type_mismatch(ctx, err)),
629 }
630 }
631 },
632 Some(_) | None => {
635 let jvalue: CedarValueJson = serde_json::from_value(val)?;
638 Ok(jvalue.into_expr(ctx)?)
639 }
640 }
641 }
642
643 fn extn_value_json_into_rexpr(
648 &self,
649 extnjson: ExtnValueJson,
650 expected_typename: Name,
651 ctx: impl Fn() -> JsonDeserializationErrorContext + Clone,
652 ) -> Result<RestrictedExpr, JsonDeserializationError> {
653 match extnjson {
654 ExtnValueJson::ExplicitExprEscape { __expr } => {
655 Err(JsonDeserializationError::ExprTag(Box::new(ctx())))
656 }
657 ExtnValueJson::ExplicitExtnEscape { __extn }
658 | ExtnValueJson::ImplicitExtnEscape(__extn) => {
659 let jvalue = CedarValueJson::ExtnEscape { __extn };
661 let expr = jvalue.into_expr(ctx.clone())?;
662 match expr.expr_kind() {
663 ExprKind::ExtensionFunctionApp { .. } => Ok(expr),
664 _ => Err(JsonDeserializationError::expected_extn_value(
665 ctx(),
666 Either::Right(expr.clone().into()),
667 )),
668 }
669 }
670 ExtnValueJson::ImplicitConstructor(val) => {
671 let expected_return_type = SchemaType::Extension {
672 name: expected_typename,
673 };
674 let func = self
675 .extensions
676 .lookup_single_arg_constructor(&expected_return_type)
677 .ok_or_else(|| {
678 JsonDeserializationError::missing_implied_constructor(
679 ctx(),
680 expected_return_type,
681 )
682 })?;
683 let arg = val.into_expr(ctx.clone())?;
684 Ok(RestrictedExpr::call_extension_fn(
685 func.name().clone(),
686 vec![arg],
687 ))
688 }
689 }
690 }
691}
692
693pub trait DeserializationContext {
697 fn static_context() -> Option<JsonDeserializationErrorContext>;
700}
701
702#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
705pub struct NoStaticContext;
706
707impl DeserializationContext for NoStaticContext {
708 fn static_context() -> Option<JsonDeserializationErrorContext> {
709 None
710 }
711}
712
713#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
716#[serde(untagged)]
717#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
718#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
719pub enum EntityUidJson<Context = NoStaticContext> {
720 ExplicitExprEscape {
722 #[cfg_attr(feature = "wasm", tsify(type = "__skip"))]
724 __expr: String,
725 #[serde(skip)]
727 context: std::marker::PhantomData<Context>,
728 },
729 ExplicitEntityEscape {
731 __entity: TypeAndId,
733 },
734 ImplicitEntityEscape(TypeAndId),
737
738 FoundValue(#[cfg_attr(feature = "wasm", tsify(type = "__skip"))] serde_json::Value),
740}
741
742impl<'de, C: DeserializationContext> DeserializeAs<'de, EntityUID> for EntityUidJson<C> {
743 fn deserialize_as<D>(deserializer: D) -> Result<EntityUID, D::Error>
744 where
745 D: serde::Deserializer<'de>,
746 {
747 use serde::de::Error;
748 let context = || JsonDeserializationErrorContext::Unknown;
750 let s = EntityUidJson::<C>::deserialize(deserializer)?;
751 let euid = s.into_euid(context).map_err(Error::custom)?;
752 Ok(euid)
753 }
754}
755
756impl<C> SerializeAs<EntityUID> for EntityUidJson<C> {
757 fn serialize_as<S>(source: &EntityUID, serializer: S) -> Result<S::Ok, S::Error>
758 where
759 S: serde::Serializer,
760 {
761 let json: EntityUidJson = source.clone().into();
762 json.serialize(serializer)
763 }
764}
765
766impl<C: DeserializationContext> EntityUidJson<C> {
767 pub fn new(entity_type: impl Into<SmolStr>, id: impl Into<SmolStr>) -> Self {
771 Self::ImplicitEntityEscape(TypeAndId {
772 entity_type: entity_type.into(),
773 id: id.into(),
774 })
775 }
776
777 pub fn into_euid(
779 self,
780 dynamic_ctx: impl Fn() -> JsonDeserializationErrorContext + Clone,
781 ) -> Result<EntityUID, JsonDeserializationError> {
782 let ctx = || C::static_context().unwrap_or_else(&dynamic_ctx);
783 match self {
784 Self::ExplicitEntityEscape { __entity } | Self::ImplicitEntityEscape(__entity) => {
785 let jvalue = CedarValueJson::EntityEscape { __entity };
787 let expr = jvalue.into_expr(ctx)?;
788 match expr.expr_kind() {
789 ExprKind::Lit(Literal::EntityUID(euid)) => Ok((**euid).clone()),
790 _ => Err(JsonDeserializationError::expected_entity_ref(
791 ctx(),
792 Either::Right(expr.clone().into()),
793 )),
794 }
795 }
796 Self::FoundValue(v) => Err(JsonDeserializationError::expected_entity_ref(
797 ctx(),
798 Either::Left(v),
799 )),
800 Self::ExplicitExprEscape { __expr, .. } => {
801 Err(JsonDeserializationError::ExprTag(Box::new(ctx())))
802 }
803 }
804 }
805}
806
807impl From<EntityUID> for EntityUidJson {
809 fn from(uid: EntityUID) -> EntityUidJson {
810 EntityUidJson::ExplicitEntityEscape {
811 __entity: uid.into(),
812 }
813 }
814}
815
816impl From<&EntityUID> for EntityUidJson {
818 fn from(uid: &EntityUID) -> EntityUidJson {
819 EntityUidJson::ExplicitEntityEscape {
820 __entity: uid.into(),
821 }
822 }
823}
824
825#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
828#[serde(untagged)]
829pub enum ExtnValueJson {
830 ExplicitExprEscape {
832 __expr: String,
834 },
835 ExplicitExtnEscape {
837 __extn: FnAndArg,
839 },
840 ImplicitExtnEscape(FnAndArg),
843 ImplicitConstructor(CedarValueJson),
849}