From d0336078c5b63b174e7313d54d973a1832228928 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Thu, 25 Jun 2026 14:39:00 +0900 Subject: feat(external-packages,shim): implement impl todos across components Port seld/jsonlint JsonParser (+hand-written Lexer), unblocking 10 json_file parse-error tests verified byte-for-byte against PHP. Implement Symfony Finder SplFileInfo, executable finders, String classes (byte/code-point/unicode), ZipArchive shim (via the zip crate), SPDX license validation, and shim date/stream functions. Genuinely-blocked sites (reflection, PHP runtime constants, non-UTF-8 transcoding, recursive PCRE) stay todo!() with reasons. Co-Authored-By: Claude Opus 4.8 (1M context) --- crates/shirabe-php-shim/src/stream.rs | 48 ++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 7 deletions(-) (limited to 'crates/shirabe-php-shim/src/stream.rs') diff --git a/crates/shirabe-php-shim/src/stream.rs b/crates/shirabe-php-shim/src/stream.rs index e5e5200..f5582a7 100644 --- a/crates/shirabe-php-shim/src/stream.rs +++ b/crates/shirabe-php-shim/src/stream.rs @@ -13,6 +13,8 @@ pub fn stream_get_contents(stream: &PhpResource) -> Option { } pub fn stream_resolve_include_path(filename: &str) -> Option { + // TODO(phase-d): resolution searches the `include_path` ini setting, which the shim does not + // model; checking only the current directory would silently miss configured include paths. let _ = filename; todo!() } @@ -60,19 +62,49 @@ fn stream_read_remaining(stream: &PhpResource, max_length: Option) -> Optio } } +// A stream context is modeled as an object holding the two arrays PHP keeps for it: the per-wrapper +// `options` and the `params`. This is a self-contained value, so it round-trips through the +// accessors below without any registry. pub fn stream_context_create( - _options: &IndexMap, - _params: Option<&IndexMap>, + options: &IndexMap, + params: Option<&IndexMap>, ) -> PhpMixed { - todo!() + let mut context = IndexMap::new(); + context.insert("options".to_string(), PhpMixed::Array(options.clone())); + context.insert( + "params".to_string(), + PhpMixed::Array(params.cloned().unwrap_or_default()), + ); + PhpMixed::Object(context) } -pub fn stream_context_get_options(_stream_or_context: &PhpMixed) -> IndexMap { - todo!() +pub fn stream_context_get_options(stream_or_context: &PhpMixed) -> IndexMap { + match stream_or_context { + PhpMixed::Object(context) | PhpMixed::Array(context) => context + .get("options") + .and_then(PhpMixed::as_array) + .cloned() + .unwrap_or_default(), + _ => IndexMap::new(), + } } -pub fn stream_context_get_params(_stream_or_context: &PhpMixed) -> IndexMap { - todo!() +pub fn stream_context_get_params(stream_or_context: &PhpMixed) -> IndexMap { + let (options, params) = match stream_or_context { + PhpMixed::Object(context) | PhpMixed::Array(context) => ( + context.get("options").cloned().unwrap_or_default(), + context + .get("params") + .and_then(PhpMixed::as_array) + .cloned() + .unwrap_or_default(), + ), + _ => (PhpMixed::default(), IndexMap::new()), + }; + // PHP exposes the wrapper options under an "options" key alongside the params. + let mut result = params; + result.insert("options".to_string(), options); + result } pub fn stream_isatty(stream: PhpResource) -> bool { @@ -80,6 +112,8 @@ pub fn stream_isatty(stream: PhpResource) -> bool { } pub fn stream_get_wrappers() -> Vec { + // TODO(phase-d): the registered wrapper set depends on compiled-in extensions and runtime + // `stream_wrapper_register` calls; neither is modeled, so a fixed list would be inaccurate. todo!() } -- cgit v1.3.1