diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-20 14:57:38 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-20 15:08:49 +0900 |
| commit | ac544bc3e1cb90cdcce4636654d0e266a78a2f85 (patch) | |
| tree | bc2ad0f64c52cc6ea1de846faec1ac3a3048a61e /crates/shirabe-php-shim/src | |
| parent | f6dd10ff812c445fe738b0feaf8e84e827ca8f9f (diff) | |
| download | php-shirabe-ac544bc3e1cb90cdcce4636654d0e266a78a2f85.tar.gz php-shirabe-ac544bc3e1cb90cdcce4636654d0e266a78a2f85.tar.zst php-shirabe-ac544bc3e1cb90cdcce4636654d0e266a78a2f85.zip | |
feat(php-shim): implement array_replace_recursive
Was a todo!() that panicked while building HTTP downloader options
(browse, and the stream/remote filesystem option merging). Recurses only
when both the existing and replacing value are arrays, merging assoc
arrays by key and lists by index; otherwise the replacing value wins.
Verified against PHP on a nested http/ssl option structure.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe-php-shim/src')
| -rw-r--r-- | crates/shirabe-php-shim/src/lib.rs | 63 |
1 files changed, 60 insertions, 3 deletions
diff --git a/crates/shirabe-php-shim/src/lib.rs b/crates/shirabe-php-shim/src/lib.rs index c30c434..4f7b4d2 100644 --- a/crates/shirabe-php-shim/src/lib.rs +++ b/crates/shirabe-php-shim/src/lib.rs @@ -1900,10 +1900,67 @@ where } pub fn array_replace_recursive( - _base: IndexMap<String, PhpMixed>, - _replacement: IndexMap<String, PhpMixed>, + mut base: IndexMap<String, PhpMixed>, + replacement: IndexMap<String, PhpMixed>, ) -> IndexMap<String, PhpMixed> { - todo!() + for (key, replacement_value) in replacement { + let merged = match base.get(&key) { + Some(base_value) => { + array_replace_recursive_value(base_value.clone(), replacement_value) + } + None => replacement_value, + }; + base.insert(key, merged); + } + base +} + +// PHP recurses only when both the existing and the replacing value are arrays; +// otherwise the replacing value wins outright. +fn array_replace_recursive_value(base: PhpMixed, replacement: PhpMixed) -> PhpMixed { + match (base, replacement) { + (PhpMixed::Array(base), PhpMixed::Array(replacement)) => { + PhpMixed::Array(array_replace_recursive_assoc(base, replacement)) + } + (PhpMixed::List(base), PhpMixed::List(replacement)) => { + PhpMixed::List(array_replace_recursive_list(base, replacement)) + } + (_, replacement) => replacement, + } +} + +fn array_replace_recursive_assoc( + mut base: IndexMap<String, Box<PhpMixed>>, + replacement: IndexMap<String, Box<PhpMixed>>, +) -> IndexMap<String, Box<PhpMixed>> { + for (key, replacement_value) in replacement { + let merged = match base.get(&key) { + Some(base_value) => Box::new(array_replace_recursive_value( + (**base_value).clone(), + *replacement_value, + )), + None => replacement_value, + }; + base.insert(key, merged); + } + base +} + +fn array_replace_recursive_list( + mut base: Vec<Box<PhpMixed>>, + replacement: Vec<Box<PhpMixed>>, +) -> Vec<Box<PhpMixed>> { + for (index, replacement_value) in replacement.into_iter().enumerate() { + if index < base.len() { + base[index] = Box::new(array_replace_recursive_value( + (*base[index]).clone(), + *replacement_value, + )); + } else { + base.push(replacement_value); + } + } + base } pub const PHP_MAJOR_VERSION: i64 = 8; |
