-
Notifications
You must be signed in to change notification settings - Fork 139
Skip intermediate serde_json::Value allocation for Context::from_serde() #2265
Description
Category
User level API features/changes
Describe the feature you'd like to request
We're using Cedar as an embedded authorization engine in a Rust financial governance system (product lifecycle management, trading entitlements, pre-trade checks). In this setup, the authorization context is already a Rust struct (or a "rkyv" object), so it never arrives as JSON.
Currently, building a Context requires going through serde_json::Value:
// Our Rust struct → serde_json::Value → Cedar Context
let json_value = serde_json::to_value(&our_context)?;
let cedar_ctx = Context::from_json_value(json_value, Some((&schema, &action)))?;This allocates an intermediate HashMap<String, Value> plus individual Value nodes that Cedar then converts into its internal restricted expression representation.
For typical web-service authorization (one check per HTTP request), this is negligible. But for high-frequency embedded use cases such as pre-trade entitlement checks, streaming risk limit validation, batch authorization over thousands of entities, the per-check allocation overhead becomes measurable.
Proposed API:
impl Context {
/// Build a Context directly from any Serialize type, skipping the
/// intermediate serde_json::Value allocation.
pub fn from_serde<T: Serialize>(
value: &T,
schema: Option<(&Schema, &EntityUid)>,
) -> Result<Self, ContextJsonError>;
}This would deserialize directly into Cedar's internal representation (restricted expressions) without the intermediate JSON value tree. The same approach could benefit Entities::from_json_value() for similar reasons.
Describe alternatives you've considered
Alternatives considered:
1. Pre-allocating and reusing a serde_json::Value buffer
We could build the Value once and then mutate field values in place between checks. This would avoid repeated allocation, but would then require careful lifetime management and we would still pay the cost of converting Value to restricted expression on every call.
2. Caching Context objects
For checks where the context is identical (in our use-case e.g. same jurisdiction, same suitability class), we could cache the constructed Context. This would likely help when many entities share the same context attributes, but wouldn't help when context varies per check (e.g., different delegation chains, per-entity suitability).
3. Using cedar-policy-core directly
We could theoretically bypass the public cedar-policy API and construct ast::Context from restricted expressions directly. This would skip JSON entirely, but it would also couple us to Cedar's internal representation which isn't part of the public API contract and could break across versions.
Where Option 3 is the most performant today but also the least sustainable. A public from_serde path would give the same performance with API stability guarantees. Hence the feature request...
Additional context
No response
Is this something that you'd be interested in working on?
- 👋 I may be able to implement this feature request
-
⚠️ This feature might incur a breaking change