-
Notifications
You must be signed in to change notification settings - Fork 107
Description
Category
User level API features/changes
Describe the feature you'd like to request
As a developer working on translation of user-defined rust types to cedar_policy::Context
, I find that I often want to reach for a merge
method to merge two contexts ctx1.merge(ctx2)
. A use-case for this is when translating nested structs of attributes into a nested Context
.
Consider a top-level aggregate of multiple user-defined Contexts.
#[derive(Builder, Debug, Clone, PartialEq, Eq)]
#[builder(pattern = "owned")]
pub struct MyContext {
pub foo: FooContext,
pub bar: BarContext,
}
Where sub-contexts may have other nested user-defined Contexts that I need to translate into a cedar_policy::Context
, are defined as:
// Contains other Contexts I need to translate, recursively.
pub struct FooContext {
pub ctx_a: Option<FooContextA>,
pub ctx_b: Option<FooContextB>,
}
// A leaf Context.
pub struct BarContext {
pub key: String,
pub value: String,
}
A merge API could help write code like this to stitch together sub-context translation results:
impl MyContext {
pub fn try_into_cedar_context(self) -> Result<cedar_policy::Context, MyContextToCedarContextError> {
let foo_ctx = self.foo.try_into_cedar_context()?;
let bar_ctx = self.bar.try_into_cedar_context()?;
Ok(foo_ctx.merge(bar_ctx));
}
}
// Example impl for a non-top-level context.
impl FooContext {
// It would be good to run a fold/collect to reduce over the contexts. Rough idea, may not compile.
pub fn try_into_cedar_context(self) -> Result<cedar_policy::Context, MyContextToCedarContextError> {
Ok(vec![self.ctx_a, self.ctx_b].iter()
.fold(Context::new(), |mut acc, ctx| {
acc.merge(ctx);
acc
})?);
}
}
Describe alternatives you've considered
Aside from the merge
proposal another good alternative could be implementing the extend
trait like HashMap
does, https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.extend.
The workaround that I ended up doing was to implement non-top-level translations to a HashMap<String, RestrictedExpression>
. Then I can build the top-level context by merging the restricted expression maps and passing that to Context::from_pairs(result)
.
// Translation of a leaf context.
impl BarContext {
pub fn try_into_cedar_context(self) -> Result<HashMap<String, RestrictedExpression, MyContextToCedarContextError> {
Ok(HashMap::from([
("key".to_string(), RestrictedExpression::new_string(self.key)),
("value".to_string(), RestrictedExpression::new_string(self.value)),
])?);
}
}
At the top-level I converted the sub-contexts to a RestrictedExpression
record, and then used Context::from_pairs
:
impl MyContext {
pub fn try_into_cedar_context(self) -> Result<cedar_policy::Context, MyContextToCedarContextError> {
let foo_expr_map = self.foo.try_into_cedar_context()?;
let bar_expr_map = self.bar.try_into_cedar_context()?;
Ok(Context::from_pairs([
("foo".to_string(), RestrictedExpression::new_record(foo_expr_map.into_iter())?),
("bar".to_string(), RestrictedExpression::new_record(bar_expr_map.into_iter())?)
]))
}
}
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