From 7b5916cb4b94055fc3add17101832f6cfe3c2f60 Mon Sep 17 00:00:00 2001 From: kevin zhao Date: Wed, 12 Nov 2025 16:51:18 -0500 Subject: [PATCH] Share prefix pattern data in execpolicy2 instead of cloning --- codex-rs/execpolicy2/src/parser.rs | 7 +++++-- codex-rs/execpolicy2/src/rule.rs | 17 +++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/codex-rs/execpolicy2/src/parser.rs b/codex-rs/execpolicy2/src/parser.rs index e70a13c2ac..eb5899a061 100644 --- a/codex-rs/execpolicy2/src/parser.rs +++ b/codex-rs/execpolicy2/src/parser.rs @@ -12,6 +12,7 @@ use starlark::values::Value; use starlark::values::list::ListRef; use starlark::values::list::UnpackList; use starlark::values::none::NoneType; +use std::sync::Arc; use crate::decision::Decision; use crate::error::Error; @@ -209,11 +210,13 @@ fn policy_builtins(builder: &mut GlobalsBuilder) { .split_first() .ok_or_else(|| Error::InvalidPattern("pattern cannot be empty".to_string()))?; + let rest: Arc<[PatternToken]> = remaining_tokens.to_vec().into(); + for head in first_token.alternatives() { let rule = Rule::Prefix(PrefixRule { pattern: PrefixPattern { - first: head, - rest: remaining_tokens.to_vec(), + first: Arc::from(head.as_str()), + rest: rest.clone(), }, decision, }); diff --git a/codex-rs/execpolicy2/src/rule.rs b/codex-rs/execpolicy2/src/rule.rs index 6883db497a..ce975afd47 100644 --- a/codex-rs/execpolicy2/src/rule.rs +++ b/codex-rs/execpolicy2/src/rule.rs @@ -4,6 +4,7 @@ use crate::error::Result; use serde::Deserialize; use serde::Serialize; use shlex::try_join; +use std::sync::Arc; /// Matches a single command token, either a fixed string or one of several allowed alternatives. #[derive(Clone, Debug, Eq, PartialEq)] @@ -20,10 +21,10 @@ impl PatternToken { } } - pub fn alternatives(&self) -> Vec { + pub fn alternatives(&self) -> &[String] { match self { - Self::Single(expected) => vec![expected.clone()], - Self::Alts(alternatives) => alternatives.clone(), + Self::Single(expected) => std::slice::from_ref(expected), + Self::Alts(alternatives) => alternatives, } } } @@ -38,14 +39,14 @@ impl std::fmt::Display for PatternToken { /// First token is fixed since we key by the first token in policy. #[derive(Clone, Debug, Eq, PartialEq)] pub struct PrefixPattern { - pub first: String, - pub rest: Vec, + pub first: Arc, + pub rest: Arc<[PatternToken]>, } impl PrefixPattern { pub fn matches_prefix(&self, cmd: &[String]) -> Option> { let pattern_length = self.rest.len() + 1; - if cmd.len() < pattern_length || cmd[0] != self.first { + if cmd.len() < pattern_length || cmd[0] != self.first.as_ref() { return None; } @@ -122,7 +123,7 @@ impl std::fmt::Display for RuleMatch { impl Rule { pub fn program(&self) -> &str { match self { - Self::Prefix(rule) => &rule.pattern.first, + Self::Prefix(rule) => rule.pattern.first.as_ref(), } } @@ -192,7 +193,7 @@ fn join_command(command: &[String]) -> String { } fn render_pattern(pattern: &PrefixPattern) -> String { - let mut tokens = vec![pattern.first.clone()]; + let mut tokens = vec![pattern.first.as_ref().to_string()]; tokens.extend(pattern.rest.iter().map(render_pattern_token)); tokens.join(", ") }