Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/builtins/azure_policy/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ pub fn resolve_path(root: &Value, path: &str) -> Value {
match &current {
Value::Object(map) => {
let mut next = None;
for (key, value) in map.iter() {
for (key, value) in map.iter_sorted() {
if let Value::String(ref key_str) = *key {
if strings::keys::eq(key_str, &segment) {
next = Some(value.clone());
Expand Down
12 changes: 6 additions & 6 deletions src/builtins/azure_policy/template_functions_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::lexer::Span;
use crate::value::Object;
use crate::value::Value;
use crate::Rc;

use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use anyhow::Result;

Expand Down Expand Up @@ -72,7 +72,7 @@ fn fn_intersection(
// Intersection of objects: keep key-value pairs from the first
// object only when the key exists in every other object AND
// the value is equal across all of them.
let mut result: BTreeMap<Value, Value> = first.as_ref().clone();
let mut result: Object = first.as_ref().clone();
for arg in rest {
let Value::Object(ref other) = *arg else {
return Ok(Value::Undefined);
Expand Down Expand Up @@ -114,7 +114,7 @@ fn fn_union(_span: &Span, _params: &[Ref<Expr>], args: &[Value], _strict: bool)
Value::Object(_) => {
// Union of objects: recursive merge. Nested objects are merged
// recursively; all other types (including arrays) use last-writer-wins.
let mut result = BTreeMap::<Value, Value>::new();
let mut result = Object::new();
for arg in args {
let Value::Object(ref obj) = *arg else {
return Ok(Value::Undefined);
Expand Down Expand Up @@ -264,7 +264,7 @@ fn fn_create_object(
);
}

let mut map = BTreeMap::<Value, Value>::new();
let mut map = Object::new();

for pair in args.chunks(2) {
#[allow(clippy::pattern_type_mismatch)]
Expand All @@ -280,9 +280,9 @@ fn fn_create_object(

/// Recursively merge two objects. Nested objects are merged; everything
/// else (including arrays) uses the value from `incoming`.
fn merge_objects(base: &BTreeMap<Value, Value>, overlay: &BTreeMap<Value, Value>) -> Value {
fn merge_objects(base: &Object, overlay: &Object) -> Value {
let mut result = base.clone();
for (k, v) in overlay {
for (k, v) in overlay.iter() {
#[allow(clippy::needless_borrowed_reference)]
let merged = match (result.get(k), v) {
(Some(&Value::Object(ref prev)), &Value::Object(ref next)) => merge_objects(prev, next),
Expand Down
6 changes: 3 additions & 3 deletions src/builtins/azure_policy/template_functions_misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::lexer::Span;
use crate::value::Object;
use crate::value::Value;
use crate::Rc;

use alloc::collections::BTreeMap;
use alloc::string::{String, ToString as _};
use alloc::vec::Vec;
use anyhow::Result;
Expand Down Expand Up @@ -84,8 +84,8 @@ fn fn_items(_span: &Span, _params: &[Ref<Expr>], args: &[Value], _strict: bool)
return Ok(Value::Undefined);
};
let mut result = Vec::with_capacity(obj.len());
for (k, v) in obj.as_ref() {
let mut entry = BTreeMap::<Value, Value>::new();
for (k, v) in obj.iter_sorted() {
let mut entry = Object::new();
entry.insert(Value::from("key"), k.clone());
entry.insert(Value::from("value"), v.clone());
result.push(Value::Object(Rc::new(entry)));
Expand Down
2 changes: 1 addition & 1 deletion src/builtins/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ fn urlquery_encode_object(

{
let mut pairs = url.query_pairs_mut();
for (key, value) in obj.iter() {
for (key, value) in obj.iter_sorted() {
let key = ensure_string(name, &params[0], key)?;
match value {
Value::String(v) => {
Expand Down
7 changes: 4 additions & 3 deletions src/builtins/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{enforce_limit, ensure_args_count, ensure_object};
use crate::lexer::Span;
use crate::value::Object;
use crate::value::Value;
use crate::*;

use alloc::collections::{BTreeMap, BTreeSet};
use alloc::collections::BTreeSet;

use anyhow::{bail, Result};

Expand Down Expand Up @@ -80,7 +81,7 @@ fn reachable(span: &Span, params: &[Ref<Expr>], args: &[Value], strict: bool) ->
}

fn visit(
graph: &BTreeMap<Value, Value>,
graph: &Object,
visited: &mut BTreeSet<Value>,
node: &Value,
path: &mut Vec<Value>,
Expand Down Expand Up @@ -211,7 +212,7 @@ fn walk_visit(path: &mut Vec<Value>, value: &Value, paths: &mut Vec<Value>) -> R
}
}
Value::Object(obj) => {
for (key, value) in obj.iter() {
for (key, value) in obj.iter_sorted() {
path.push(key.clone());
// Guard path stack growth while traversing object entries.
enforce_limit()?;
Expand Down
2 changes: 1 addition & 1 deletion src/builtins/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ fn merge_filters(
let vref = match f {
Value::Object(obj) => {
let obj = Rc::make_mut(obj);
let entry = obj.entry(p.clone()).or_insert_with(Value::new_object);
let entry = obj.get_or_insert_with(p.clone(), Value::new_object);
// Guard filter map growth when creating nested objects.
enforce_limit()?;
entry
Expand Down
4 changes: 2 additions & 2 deletions src/builtins/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ fn to_string(v: &Value, unescape: bool) -> String {
}
Value::Object(o) => {
"{".to_owned()
+ &o.iter()
+ &o.iter_sorted()
.map(|(k, v)| to_string(k, true) + ": " + &to_string(v, true))
.collect::<Vec<String>>()
.join(", ")
Expand Down Expand Up @@ -568,7 +568,7 @@ fn replace_n(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -
let mut s = ensure_string(name, &params[1], &args[1])?;

let span = params[0].span();
for item in obj.as_ref().iter() {
for item in obj.as_ref().iter_sorted() {
match item {
(Value::String(k), Value::String(v)) => {
s = s.replace(k.as_ref(), v.as_ref()).into();
Expand Down
5 changes: 3 additions & 2 deletions src/builtins/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
use crate::ast::{Expr, Ref};
use crate::lexer::Span;
use crate::number::Number;
use crate::value::Object;
use crate::Rc;
use crate::Value;
use crate::*;

use alloc::collections::{BTreeMap, BTreeSet};
use alloc::collections::BTreeSet;

use anyhow::{bail, Result};

Expand Down Expand Up @@ -168,7 +169,7 @@ pub fn ensure_set(fcn: &str, arg: &Expr, v: Value) -> Result<Rc<BTreeSet<Value>>
})
}

pub fn ensure_object(fcn: &str, arg: &Expr, v: Value) -> Result<Rc<BTreeMap<Value, Value>>> {
pub fn ensure_object(fcn: &str, arg: &Expr, v: Value) -> Result<Rc<Object>> {
Ok(match v {
Value::Object(o) => o,
_ => {
Expand Down
60 changes: 21 additions & 39 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ use crate::{Expression, Extension, Location, QueryResult, QueryResults};
use crate::query::traversal::traverse;

use crate::Rc;
use alloc::collections::btree_map::Entry as BTreeMapEntry;
use alloc::collections::{BTreeMap, BTreeSet};
use anyhow::{anyhow, bail, Result};
use core::ops::Bound::*;
Expand Down Expand Up @@ -1312,10 +1311,10 @@ impl Interpreter {
*obj = Value::new_object();
}

obj = obj
.as_object_mut()?
.entry(Value::String(p.to_string().into()))
.or_insert(Value::new_object());
obj = obj.as_object_mut()?.get_or_insert_with(
Value::String(p.to_string().into()),
Value::new_object,
);
}
*obj = value;
// Mark modified rules as processed.
Expand Down Expand Up @@ -1682,29 +1681,21 @@ impl Interpreter {
let set = obj
.as_object_mut()
.map_err(|_| anyhow!(span.error("previous value is not an object")))?
.entry(p)
.or_insert(Value::new_set())
.get_or_insert_with(p, Value::new_set)
.as_set_mut()
.map_err(|_| anyhow!(span.error("previous value is not a set")))?;
set.append(value.as_set_mut()?);
} else {
let obj = obj
.as_object_mut()
.map_err(|_| anyhow!(span.error("previous value is not an object")))?;
match obj.entry(p) {
BTreeMapEntry::Vacant(v) => {
if value != Value::Undefined {
v.insert(value);
} else {
// TODO: clean this assumption between Undefined vs Object.
v.insert(Value::new_object());
}
}
BTreeMapEntry::Occupied(o) => {
if o.get() != &value && value != Value::Undefined {
bail!(span
.error("complete rules should not produce multiple outputs"))
}
if value == Value::Undefined {
// TODO: clean this assumption between Undefined vs Object.
obj.get_or_insert_with(p, Value::new_object);
} else {
let existing = obj.get_or_insert_with(p, || value.clone());
if *existing != value {
bail!(span.error("complete rules should not produce multiple outputs"))
}
}
}
Expand All @@ -1713,8 +1704,7 @@ impl Interpreter {
obj = obj
.as_object_mut()
.map_err(|_| anyhow!(span.error("previous value is not an object")))?
.entry(p)
.or_insert(Value::new_object());
.get_or_insert_with(p, Value::new_object);
}
}
Ok(())
Expand Down Expand Up @@ -1822,8 +1812,7 @@ impl Interpreter {
let set = ctx_mut
.rule_value
.as_object_mut()?
.entry(Value::from_array(comps))
.or_insert(Value::new_set());
.get_or_insert_with(Value::from_array(comps), Value::new_set);
if output != Value::Undefined {
set.as_set_mut()?.insert(output);
return Ok(true);
Expand All @@ -1832,20 +1821,13 @@ impl Interpreter {
}

// Non-set rule.
match ctx_mut
.rule_value
.as_object_mut()?
.entry(Value::from_array(comps))
{
BTreeMapEntry::Vacant(v) => {
v.insert(output);
}
BTreeMapEntry::Occupied(o) if o.get() != &output => bail!(rule_ref
let key = Value::from_array(comps);
let obj_mut = ctx_mut.rule_value.as_object_mut()?;
let existing = obj_mut.get_or_insert_with(key, || output.clone());
if *existing != output {
bail!(rule_ref
.span()
.error("rules must not produce multiple outputs")),
_ => {
// Rule produced same value.
}
.error("rules must not produce multiple outputs"));
}

return Ok(true);
Expand Down Expand Up @@ -2471,7 +2453,7 @@ impl Interpreter {
}
Value::Object(map) => {
s.push('{');
for (idx, (k, entry_value)) in map.iter().enumerate() {
for (idx, (k, entry_value)) in map.iter_sorted().enumerate() {
if idx > 0 {
s.push_str(", ");
}
Expand Down
4 changes: 2 additions & 2 deletions src/languages/azure_policy/aliases/denormalizer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@ pub fn denormalize_with_aliases(
// Phase 4: Attach properties to result.
if !properties.is_empty() {
if let Some(Value::Object(existing_rc)) = result.get_mut("properties") {
// Merge directly into the BTreeMap, avoiding full ObjMap round-trip.
// Merge directly into the Object, avoiding full ObjMap round-trip.
let existing = Rc::make_mut(existing_rc);
for (k, v) in properties {
existing.entry(Value::String(k)).or_insert(v);
existing.get_or_insert_with(Value::String(k), || v);
}
} else {
obj_insert(&mut result, "properties", make_value(properties));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use alloc::collections::{BTreeMap, BTreeSet};
use alloc::string::String;
use alloc::vec::Vec;

use crate::value::Object;
use crate::Value;

use super::super::obj_map::{make_value, new_map, obj_insert, val_str, ObjMap};
Expand Down Expand Up @@ -141,7 +142,7 @@ fn rewrap_nested_array(
/// BTreeMap-native recursion for nested sub-resource array re-wrapping,
/// avoiding ObjMap round-trips on each array element.
fn rewrap_nested_array_in_btree(
btree: &mut alloc::collections::BTreeMap<Value, Value>,
btree: &mut Object,
parent_parts: &[&str],
array_name: &str,
envelope_fields: &BTreeSet<String>,
Expand Down Expand Up @@ -187,10 +188,7 @@ fn rewrap_nested_array_in_btree(
}

/// Find a key in a BTreeMap using case-insensitive comparison.
fn find_key_ci_btree(
btree: &alloc::collections::BTreeMap<Value, Value>,
key: &str,
) -> Option<Value> {
fn find_key_ci_btree(btree: &Object, key: &str) -> Option<Value> {
btree
.keys()
.find(|k| val_str(k).is_some_and(|s| s.eq_ignore_ascii_case(key)))
Expand Down
21 changes: 7 additions & 14 deletions src/languages/azure_policy/aliases/normalizer/element_remap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
use alloc::string::String;
use alloc::vec::Vec;

use crate::value::Object;
use crate::Value;

use super::super::obj_map::{
obj_get, obj_get_mut, obj_insert, set_nested_in_btree, set_nested_lowercased,
set_nested_verbatim, ObjMap,
obj_get, obj_get_mut, obj_insert, set_nested, set_nested_lowercased, set_nested_verbatim,
ObjMap,
};
use super::super::types::PrecomputedRemap;

Expand Down Expand Up @@ -118,7 +119,7 @@ fn apply_remap_at_depth(
/// BTreeMap-native recursion for element-level remap, avoiding ObjMap
/// round-trips on each array element.
fn remap_at_depth_in_btree(
btree: &mut alloc::collections::BTreeMap<Value, Value>,
btree: &mut Object,
array_chain: &[Vec<String>],
depth: usize,
source_field: &str,
Expand Down Expand Up @@ -177,12 +178,7 @@ fn remap_at_depth_in_btree(
}

/// Remap a value between dotted paths directly in a BTreeMap.
fn remap_deep_field_in_btree(
btree: &mut alloc::collections::BTreeMap<Value, Value>,
source: &str,
target: &str,
lowercase: bool,
) {
fn remap_deep_field_in_btree(btree: &mut Object, source: &str, target: &str, lowercase: bool) {
let val = match read_dotted_path_btree(btree, source) {
Some(v) => v,
None => return,
Expand All @@ -198,14 +194,11 @@ fn remap_deep_field_in_btree(
}
return;
}
set_nested_in_btree(btree, &segments, val, lowercase);
set_nested(btree, &segments, val, lowercase);
}

/// Read a value at a dotted path from a BTreeMap.
fn read_dotted_path_btree(
btree: &alloc::collections::BTreeMap<Value, Value>,
path: &str,
) -> Option<Value> {
fn read_dotted_path_btree(btree: &Object, path: &str) -> Option<Value> {
let segments: Vec<&str> = path.split('.').collect();
let first = segments.first()?;
let mut cur: &Value = btree.get(&Value::from(*first))?;
Expand Down
Loading
Loading