From 5d75947179c8c47081f276b23c2b16c2c3683b54 Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Fri, 27 Feb 2026 12:43:12 -0800 Subject: [PATCH 1/6] refactor codegen --- src/codegen.rs | 530 ------------------------------------------ src/codegen/fuzz.rs | 112 +++++++++ src/codegen/mod.rs | 233 +++++++++++++++++++ src/codegen/record.rs | 93 ++++++++ src/codegen/replay.rs | 121 ++++++++++ 5 files changed, 559 insertions(+), 530 deletions(-) delete mode 100644 src/codegen.rs create mode 100644 src/codegen/fuzz.rs create mode 100644 src/codegen/mod.rs create mode 100644 src/codegen/record.rs create mode 100644 src/codegen/replay.rs diff --git a/src/codegen.rs b/src/codegen.rs deleted file mode 100644 index 129788c..0000000 --- a/src/codegen.rs +++ /dev/null @@ -1,530 +0,0 @@ -use crate::util::{ - FullTypePath, ResourceFuncKind, extract_arg_info, get_owned_type, get_resource_from_trait_name, - get_return_type, make_path, wit_func_name, -}; -use anyhow::Result; -use quote::quote; -use std::collections::{BTreeMap, BTreeSet}; -use std::path::PathBuf; -use syn::{ - File, Ident, Item, ItemEnum, ItemStruct, ItemTrait, Signature, TraitItem, parse_quote, - visit_mut::VisitMut, -}; - -#[derive(clap::Parser)] -pub struct GenerateArgs { - /// The path to the binding file generated by wit-bindgen. - pub bindings: PathBuf, - /// Specifies the type of the WIT component. - pub mode: GenerateMode, - /// The path to the output file. - #[arg(short, long, default_value("lib.rs"))] - pub output_file: PathBuf, -} -#[derive(clap::ValueEnum, clap::Parser, Clone)] -pub enum GenerateMode { - /// An arbitrary component, we can only generate an empty stub. - Stubs, - /// An instrument component which imports and exports the same interface. - /// The generated code will redirect the export interface to call the corresponding import interface. - Instrument, - /// An instrument component which records all import calls. - Record, - /// A virtualized component with no imports, with implementation for replay. - Replay, - /// A virtualized component with no imports, with implementation for fuzzing. - Fuzz, -} -impl GenerateMode { - pub fn is_instrument(&self) -> bool { - matches!(self, GenerateMode::Instrument | GenerateMode::Record) - } -} - -pub struct State { - pub mode: GenerateMode, - pub traits: BTreeMap, Vec>, - pub types: BTreeMap, Vec>, - pub funcs: BTreeMap, BTreeMap, Vec>>, - pub module_paths: BTreeSet>, - pub output: Vec, -} -pub enum TypeInfo { - Struct(ItemStruct), - Enum(ItemEnum), - Resource(ItemStruct), - Flag(ItemFlag), -} -pub struct ItemFlag { - pub name: Ident, - pub flags: Vec, -} - -impl GenerateArgs { - pub fn generate(&self) -> Result<()> { - let file = std::fs::read_to_string(&self.bindings)?; - let ast = syn::parse_file(&file)?; - - let mut state = State { - mode: self.mode.clone(), - traits: BTreeMap::new(), - types: BTreeMap::new(), - funcs: BTreeMap::new(), - module_paths: BTreeSet::new(), - output: Vec::new(), - }; - state.generate_preamble(); - state.find_all_items(&ast.items, vec![]); - state.generate_stubs(); - let trait_generator = crate::traits::TraitGenerator::new(&state); - let traits = trait_generator.generate(); - drop(trait_generator); - state.output.extend(traits); - let file = state.into_output_file(); - let output = prettyplease::unparse(&file); - std::fs::write(&self.output_file, output)?; - Ok(()) - } -} -impl State { - fn generate_stubs(&mut self) { - for (module_path, traits) in &self.traits { - for trait_item in traits { - let impl_item = self.generate_impl_with_methods(trait_item, module_path); - self.output.push(impl_item); - } - } - } - fn generate_preamble(&mut self) { - let file: File = parse_quote! { - mod bindings; - use bindings::*; - struct Stub; - bindings::export!(Stub with_types_in bindings); - }; - self.output = file.items; - } - fn generate_impl_with_methods(&self, trait_item: &ItemTrait, module_path: &[String]) -> Item { - let trait_name = &trait_item.ident.to_string(); - let trait_path = make_path(module_path, trait_name); - let resource = get_resource_from_trait_name(trait_name); - let stub: syn::Path = match (&self.mode.is_instrument(), &resource) { - (true, Some(resource)) => { - let import_path = get_proxy_path(module_path); - make_path(&import_path, resource) - } - (false, Some(_)) => parse_quote! { MockedResource }, - (_, _) => parse_quote! { Stub }, - }; - // Collect all method signatures from the trait - let mut methods = Vec::new(); - for item in &trait_item.items { - match item { - TraitItem::Type(assoc_type) => { - let type_name = &assoc_type.ident; - let stub: syn::Path = if self.mode.is_instrument() { - let import_path = get_proxy_path(module_path); - make_path(&import_path, &type_name.to_string()) - } else { - parse_quote! { MockedResource } - }; - let impl_item = parse_quote! { - type #type_name = #stub; - }; - methods.push(syn::ImplItem::Type(impl_item)); - } - TraitItem::Fn(method) => { - if method.sig.ident.to_string().starts_with("_resource_") { - continue; - } - let mut sig = method.sig.clone(); - let mut transformer = FullTypePath { module_path }; - transformer.visit_signature_mut(&mut sig); - let stub_impl = match self.mode { - GenerateMode::Stubs => parse_quote! { - #[allow(unused_variables)] - #sig { - unimplemented!() - } - }, - GenerateMode::Instrument | GenerateMode::Record => { - if module_path.join("::") == "exports::proxy::conversion::conversion" { - self.generate_conversion_func(&sig) - } else { - self.generate_instrument_func(module_path, &sig, &resource) - } - } - GenerateMode::Replay => { - if module_path.join("::") == "exports::proxy::conversion::conversion" { - self.generate_conversion_func(&sig) - } else { - self.generate_replay_func(module_path, &sig, &resource) - } - } - GenerateMode::Fuzz => { - if module_path.join("::") == "exports::proxy::conversion::conversion" { - self.generate_conversion_func(&sig) - } else { - self.generate_fuzz_func(module_path, &sig, &resource) - } - } - }; - methods.push(syn::ImplItem::Fn(stub_impl)); - } - _ => (), - } - } - parse_quote! { - impl #trait_path for #stub { - #(#methods)* - } - } - } - fn generate_fuzz_func( - &self, - module_path: &[String], - sig: &Signature, - resource: &Option, - ) -> syn::ImplItemFn { - let func_name = &sig.ident; - let is_export = module_path.join("::") == "exports::proxy::recorder::start_replay"; - if !is_export { - let (kind, args) = extract_arg_info(sig); - let arg_names = args.iter().map(|arg| &arg.ident); - let display_name = wit_func_name(module_path, resource, func_name, &kind); - let ret_ty = get_return_type(&sig.output); - if ret_ty.is_some() { - parse_quote! { - #sig { - let mut __params: Vec = Vec::new(); - #( - __params.push(wasm_wave::to_string(&ToValue::to_value(&#arg_names)).unwrap()); - )* - let mut __buf = __params.join(","); - proxy::util::debug::print(&format!("import: {}({})", #display_name, __buf)); - __buf += #display_name; - let mut u = Unstructured::new(&__buf.as_bytes()); - let res = u.arbitrary().unwrap(); - let res_str = wasm_wave::to_string(&ToValue::to_value(&res)).unwrap(); - proxy::util::debug::print(&format!("ret: {}", res_str)); - res - } - } - } else { - parse_quote! { - #sig {} - } - } - } else { - assert!(func_name == "start"); - let arms: Vec<_> = self - .funcs - .iter() - .filter(|(path, _)| path[0] != "exports" && path[0] != "proxy") - .flat_map(|(path, resources)| { - resources.iter().flat_map(move |(resource, sigs)| { - sigs.iter().filter_map(move |sig| { - let (kind, args) = extract_arg_info(sig); - if matches!(kind, Some(ResourceFuncKind::Method)) { - return None; - } - let arg_name: Vec<_> = args.iter().map(|arg| &arg.ident).collect(); - let call_param = args.iter().map(|arg| arg.call_param()); - let ty = args.iter().map(|arg| { - let mut ty = arg.ty.clone(); - FullTypePath { module_path: path }.visit_type_mut(&mut ty); - if let Some(owned) = get_owned_type(&ty) { - owned - } else { - ty - } - }); - let func_name = if let Some(resource) = resource { - format!("{}::{}", resource, sig.ident) - } else { - sig.ident.to_string() - }; - let func = make_path(path, &func_name); - let display_name = wit_func_name(path, resource, &sig.ident, &kind); - Some(quote! { - { - let mut __params: Vec = Vec::new(); - #( - let #arg_name: #ty = u.arbitrary().unwrap(); - __params.push(wasm_wave::to_string(&ToValue::to_value(&#arg_name)).unwrap()); - )* - proxy::util::debug::print(&format!("export: {}({})", #display_name, __params.join(", "))); - let _ = #func(#(#call_param),*); - } - }) - }) - }) - }) - .collect(); - let func_len = arms.iter().len(); - let idxs = 1..=func_len; - parse_quote! { - #sig { - let __buf = proxy::util::debug::get_random(); - let mut u = Unstructured::new(&__buf); - for _ in 0..10 { - let idx = u.int_in_range(1..=#func_len).unwrap(); - match idx { - #(#idxs => #arms)* - _ => unreachable!(), - } - // clean up borrowed resources from input args - SCOPED_ALLOC.with(|alloc| { - alloc.borrow_mut().clear(); - }); - } - } - } - } - } - fn generate_replay_func( - &self, - module_path: &[String], - sig: &Signature, - resource: &Option, - ) -> syn::ImplItemFn { - let func_name = &sig.ident; - let is_export = module_path.join("::") == "exports::proxy::recorder::start_replay"; - if !is_export { - let (kind, args) = extract_arg_info(sig); - let arg_names = args.iter().map(|arg| &arg.ident); - let display_name = wit_func_name(module_path, resource, func_name, &kind); - let ret_ty = get_return_type(&sig.output); - let replay_import = if let Some(ret_ty) = ret_ty { - quote! { - let wave = proxy::recorder::replay::replay_import(Some(#display_name), Some(&args)).unwrap(); - let ret: Value = wasm_wave::from_str(&<#ret_ty as ValueTyped>::value_type(), &wave).unwrap(); - ret.to_rust() - } - } else { - quote! { - let wave = proxy::recorder::replay::replay_import(Some(#display_name), Some(&args)); - assert!(wave.is_none()); - } - }; - let self_value = if matches!(kind, Some(ResourceFuncKind::Method)) { - // Use ToValue::to_value to avoid the auto-deref from self.to_value() - quote! { wasm_wave::to_string(&ToValue::to_value(&self)).unwrap(), } - } else { - quote! {} - }; - parse_quote! { - #sig { - let args = vec![#self_value #( wasm_wave::to_string(&#arg_names.to_value()).unwrap() ),*]; - #replay_import - } - } - } else { - assert!(func_name == "start"); - let arms = self - .funcs - .iter() - .filter(|(path, _)| path[0] != "exports" && path[0] != "proxy") - .flat_map(|(path, resources)| { - resources.iter().flat_map(move |(resource, sigs)| { - sigs.iter().filter_map(move |sig| { - let (kind, args) = extract_arg_info(sig); - if matches!(kind, Some(ResourceFuncKind::Method)) { - return None; - } - let arg_name: Vec<_> = args.iter().map(|arg| &arg.ident).collect(); - let arg_idx = args.iter().enumerate().map(|(idx, _)| quote! { args[#idx] }); - let call_param = args.iter().map(|arg| arg.call_param()); - let ty = args.iter().map(|arg| { - let mut ty = arg.ty.clone(); - FullTypePath { - module_path: path, - }.visit_type_mut(&mut ty); - if let Some(owned) = get_owned_type(&ty) { - owned - } else { - ty - } - }); - let func_name = if let Some(resource) = resource { - format!("{}::{}", resource, sig.ident) - } else { - sig.ident.to_string() - }; - let func = make_path(path, &func_name); - let display_name = wit_func_name(path, resource, &sig.ident, &kind); - let assert_ret = if get_return_type(&sig.output).is_none() { - quote! { - assert!(res == ()); - proxy::recorder::replay::assert_export_ret(Some(#display_name), None); - } - } else { - quote! { - let wave_res = wasm_wave::to_string(&res.to_value()).unwrap(); - proxy::recorder::replay::assert_export_ret(Some(#display_name), Some(&wave_res)); - } - }; - Some(quote! { - #display_name => { - #( - let arg_value: Value = wasm_wave::from_str(&<#ty as ValueTyped>::value_type(), &#arg_idx).unwrap(); - let #arg_name: #ty = arg_value.to_rust(); - )* - let res = #func(#(#call_param),*); - #assert_ret - } - }) - }) - }) - }); - parse_quote! { - #sig { - while let Some((method, args)) = proxy::recorder::replay::replay_export() { - match method.as_str() { - #(#arms)* - _ => unreachable!(), - } - // clean up borrowed resources from input args - SCOPED_ALLOC.with(|alloc| { - alloc.borrow_mut().clear(); - }); - } - } - } - } - } - fn generate_instrument_func( - &self, - module_path: &[String], - sig: &Signature, - resource: &Option, - ) -> syn::ImplItemFn { - let func_name = &sig.ident; - let (kind, args) = extract_arg_info(sig); - let import_path = get_proxy_path(module_path); - let import_sig = self - .find_function(&import_path, resource, func_name) - .unwrap(); - let (_, import_args) = extract_arg_info(import_sig); - let arg_names = args.iter().map(|arg| &arg.ident); - let call_args = args - .iter() - .zip(import_args.iter()) - .map(|(arg, import_arg)| -> syn::Expr { - let ident = &arg.ident; - if import_arg.is_borrowed { - parse_quote! { &#ident } - } else { - parse_quote! { #ident } - } - }); - let (func, res): (syn::Expr, _) = match (resource.is_some(), &kind) { - (true, Some(ResourceFuncKind::Method)) => { - (parse_quote! { self.#func_name }, quote! { res.to_proxy() }) - } - (true, Some(ResourceFuncKind::Constructor)) => { - (parse_quote! { Self::#func_name }, quote! { res }) - } - (true, None) => (parse_quote! { Self::#func_name }, quote! { res.to_proxy() }), - (false, _) => ( - syn::parse_str(&format!("{}::{}", import_path.join("::"), func_name)).unwrap(), - quote! { res.to_proxy() }, - ), - }; - match &self.mode { - GenerateMode::Instrument => parse_quote! { - #sig { - let res = #func(#(#call_args.to_proxy()),*); - #res - } - }, - GenerateMode::Record => { - let init_vec = if matches!(kind, Some(ResourceFuncKind::Method)) { - quote! { vec![wasm_wave::to_string(&ToValue::to_value(&self)).unwrap()] } - } else { - quote! { Vec::new() } - }; - let is_mut = if args.is_empty() { - quote! {} - } else { - quote! { mut } - }; - let display_name = wit_func_name(module_path, resource, func_name, &kind); - let is_export = !module_path[1].starts_with("wrapped_"); - let record_ret = if get_return_type(&sig.output).is_none() { - quote! { - #func(#(#call_args),*); - proxy::recorder::record::record_ret(Some(#display_name), None, #is_export); - } - } else { - quote! { - let res = #func(#(#call_args),*); - let wave_res = wasm_wave::to_string(&res.to_value()).unwrap(); - proxy::recorder::record::record_ret(Some(#display_name), Some(&wave_res), #is_export); - #res - } - }; - parse_quote! { - #sig { - let #is_mut params: Vec = #init_vec; - #( - let #arg_names = #arg_names.to_proxy(); - params.push(wasm_wave::to_string(&ToValue::to_value(&#arg_names)).unwrap()); - )* - proxy::recorder::record::record_args(Some(#display_name), ¶ms, #is_export); - #record_ret - } - } - } - _ => unreachable!(), - } - } - fn generate_conversion_func(&self, sig: &Signature) -> syn::ImplItemFn { - let func_name = &sig.ident.to_string(); - let body = if func_name.starts_with("get_wrapped_") { - quote! { x.to_proxy() } - } else if func_name.starts_with("get_host_") { - quote! { x.to_proxy() } - } else if func_name.starts_with("get_mock_") { - let resource = get_return_type(&sig.output).unwrap(); - let name = func_name - .rfind("_magic42_") - .map(|idx| &func_name[idx + 9..]) - .unwrap(); - quote! { - #resource::new(MockedResource { handle, name: #name.to_string() }) - } - } else { - unreachable!() - }; - parse_quote! { - #sig { - #body - } - } - } - fn into_output_file(self) -> File { - File { - items: self.output, - shebang: None, - attrs: Vec::new(), - } - } -} - -pub fn get_proxy_path(src_path: &[String]) -> Vec { - assert!(src_path.len() >= 3); - let mut res = src_path.to_vec(); - let mut wrapped_idx = 0; - if res[0] == "exports" { - res.remove(0); - } else { - res.insert(0, "exports".to_string()); - wrapped_idx = 1; - } - match res[wrapped_idx].strip_prefix("wrapped_") { - Some(name) => res[wrapped_idx] = name.to_string(), - None => res[wrapped_idx] = "wrapped_".to_string() + &res[wrapped_idx], - } - res -} diff --git a/src/codegen/fuzz.rs b/src/codegen/fuzz.rs new file mode 100644 index 0000000..d5bda0b --- /dev/null +++ b/src/codegen/fuzz.rs @@ -0,0 +1,112 @@ +use super::State; +use crate::util::{ + FullTypePath, ResourceFuncKind, extract_arg_info, get_owned_type, get_return_type, make_path, + wit_func_name, +}; +use quote::quote; +use syn::{Signature, parse_quote, visit_mut::VisitMut}; + +impl State { + pub fn generate_fuzz_func( + &self, + module_path: &[String], + sig: &Signature, + resource: &Option, + ) -> syn::ImplItemFn { + let func_name = &sig.ident; + let is_export = module_path.join("::") == "exports::proxy::recorder::start_replay"; + if !is_export { + let (kind, args) = extract_arg_info(sig); + let arg_names = args.iter().map(|arg| &arg.ident); + let display_name = wit_func_name(module_path, resource, func_name, &kind); + let ret_ty = get_return_type(&sig.output); + if ret_ty.is_some() { + parse_quote! { + #sig { + let mut __params: Vec = Vec::new(); + #( + __params.push(wasm_wave::to_string(&ToValue::to_value(&#arg_names)).unwrap()); + )* + let mut __buf = __params.join(","); + proxy::util::debug::print(&format!("import: {}({})", #display_name, __buf)); + __buf += #display_name; + let mut u = Unstructured::new(&__buf.as_bytes()); + let res = u.arbitrary().unwrap(); + let res_str = wasm_wave::to_string(&ToValue::to_value(&res)).unwrap(); + proxy::util::debug::print(&format!("ret: {}", res_str)); + res + } + } + } else { + parse_quote! { + #sig {} + } + } + } else { + assert!(func_name == "start"); + let arms: Vec<_> = self + .funcs + .iter() + .filter(|(path, _)| path[0] != "exports" && path[0] != "proxy") + .flat_map(|(path, resources)| { + resources.iter().flat_map(move |(resource, sigs)| { + sigs.iter().filter_map(move |sig| { + let (kind, args) = extract_arg_info(sig); + if matches!(kind, Some(ResourceFuncKind::Method)) { + return None; + } + let arg_name: Vec<_> = args.iter().map(|arg| &arg.ident).collect(); + let call_param = args.iter().map(|arg| arg.call_param()); + let ty = args.iter().map(|arg| { + let mut ty = arg.ty.clone(); + FullTypePath { module_path: path }.visit_type_mut(&mut ty); + if let Some(owned) = get_owned_type(&ty) { + owned + } else { + ty + } + }); + let func_name = if let Some(resource) = resource { + format!("{}::{}", resource, sig.ident) + } else { + sig.ident.to_string() + }; + let func = make_path(path, &func_name); + let display_name = wit_func_name(path, resource, &sig.ident, &kind); + Some(quote! { + { + let mut __params: Vec = Vec::new(); + #( + let #arg_name: #ty = u.arbitrary().unwrap(); + __params.push(wasm_wave::to_string(&ToValue::to_value(&#arg_name)).unwrap()); + )* + proxy::util::debug::print(&format!("export: {}({})", #display_name, __params.join(", "))); + let _ = #func(#(#call_param),*); + } + }) + }) + }) + }) + .collect(); + let func_len = arms.iter().len(); + let idxs = 1..=func_len; + parse_quote! { + #sig { + let __buf = proxy::util::debug::get_random(); + let mut u = Unstructured::new(&__buf); + for _ in 0..10 { + let idx = u.int_in_range(1..=#func_len).unwrap(); + match idx { + #(#idxs => #arms)* + _ => unreachable!(), + } + // clean up borrowed resources from input args + SCOPED_ALLOC.with(|alloc| { + alloc.borrow_mut().clear(); + }); + } + } + } + } + } +} diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs new file mode 100644 index 0000000..41fc62f --- /dev/null +++ b/src/codegen/mod.rs @@ -0,0 +1,233 @@ +use crate::util::{FullTypePath, get_resource_from_trait_name, get_return_type, make_path}; +use anyhow::Result; +use quote::quote; +use std::collections::{BTreeMap, BTreeSet}; +use std::path::PathBuf; +use syn::{ + File, Ident, Item, ItemEnum, ItemStruct, ItemTrait, Signature, TraitItem, parse_quote, + visit_mut::VisitMut, +}; + +mod fuzz; +mod record; +mod replay; + +#[derive(clap::Parser)] +pub struct GenerateArgs { + /// The path to the binding file generated by wit-bindgen. + pub bindings: PathBuf, + /// Specifies the type of the WIT component. + pub mode: GenerateMode, + /// The path to the output file. + #[arg(short, long, default_value("lib.rs"))] + pub output_file: PathBuf, +} +#[derive(clap::ValueEnum, clap::Parser, Clone)] +pub enum GenerateMode { + /// An arbitrary component, we can only generate an empty stub. + Stubs, + /// An instrument component which imports and exports the same interface. + /// The generated code will redirect the export interface to call the corresponding import interface. + Instrument, + /// An instrument component which records all import calls. + Record, + /// A virtualized component with no imports, with implementation for replay. + Replay, + /// A virtualized component with no imports, with implementation for fuzzing. + Fuzz, +} +impl GenerateMode { + pub fn is_instrument(&self) -> bool { + matches!(self, GenerateMode::Instrument | GenerateMode::Record) + } +} + +pub struct State { + pub mode: GenerateMode, + pub traits: BTreeMap, Vec>, + pub types: BTreeMap, Vec>, + pub funcs: BTreeMap, BTreeMap, Vec>>, + pub module_paths: BTreeSet>, + pub output: Vec, +} +pub enum TypeInfo { + Struct(ItemStruct), + Enum(ItemEnum), + Resource(ItemStruct), + Flag(ItemFlag), +} +pub struct ItemFlag { + pub name: Ident, + pub flags: Vec, +} + +impl GenerateArgs { + pub fn generate(&self) -> Result<()> { + let file = std::fs::read_to_string(&self.bindings)?; + let ast = syn::parse_file(&file)?; + + let mut state = State { + mode: self.mode.clone(), + traits: BTreeMap::new(), + types: BTreeMap::new(), + funcs: BTreeMap::new(), + module_paths: BTreeSet::new(), + output: Vec::new(), + }; + state.generate_preamble(); + state.find_all_items(&ast.items, vec![]); + state.generate_stubs(); + let trait_generator = crate::traits::TraitGenerator::new(&state); + let traits = trait_generator.generate(); + drop(trait_generator); + state.output.extend(traits); + let file = state.into_output_file(); + let output = prettyplease::unparse(&file); + std::fs::write(&self.output_file, output)?; + Ok(()) + } +} +impl State { + fn generate_stubs(&mut self) { + for (module_path, traits) in &self.traits { + for trait_item in traits { + let impl_item = self.generate_impl_with_methods(trait_item, module_path); + self.output.push(impl_item); + } + } + } + fn generate_preamble(&mut self) { + let file: File = parse_quote! { + mod bindings; + use bindings::*; + struct Stub; + bindings::export!(Stub with_types_in bindings); + }; + self.output = file.items; + } + fn generate_impl_with_methods(&self, trait_item: &ItemTrait, module_path: &[String]) -> Item { + let trait_name = &trait_item.ident.to_string(); + let trait_path = make_path(module_path, trait_name); + let resource = get_resource_from_trait_name(trait_name); + let stub: syn::Path = match (&self.mode.is_instrument(), &resource) { + (true, Some(resource)) => { + let import_path = get_proxy_path(module_path); + make_path(&import_path, resource) + } + (false, Some(_)) => parse_quote! { MockedResource }, + (_, _) => parse_quote! { Stub }, + }; + // Collect all method signatures from the trait + let mut methods = Vec::new(); + for item in &trait_item.items { + match item { + TraitItem::Type(assoc_type) => { + let type_name = &assoc_type.ident; + let stub: syn::Path = if self.mode.is_instrument() { + let import_path = get_proxy_path(module_path); + make_path(&import_path, &type_name.to_string()) + } else { + parse_quote! { MockedResource } + }; + let impl_item = parse_quote! { + type #type_name = #stub; + }; + methods.push(syn::ImplItem::Type(impl_item)); + } + TraitItem::Fn(method) => { + if method.sig.ident.to_string().starts_with("_resource_") { + continue; + } + let mut sig = method.sig.clone(); + let mut transformer = FullTypePath { module_path }; + transformer.visit_signature_mut(&mut sig); + let stub_impl = match self.mode { + GenerateMode::Stubs => parse_quote! { + #[allow(unused_variables)] + #sig { + unimplemented!() + } + }, + GenerateMode::Instrument | GenerateMode::Record => { + if module_path.join("::") == "exports::proxy::conversion::conversion" { + self.generate_conversion_func(&sig) + } else { + self.generate_instrument_func(module_path, &sig, &resource) + } + } + GenerateMode::Replay => { + if module_path.join("::") == "exports::proxy::conversion::conversion" { + self.generate_conversion_func(&sig) + } else { + self.generate_replay_func(module_path, &sig, &resource) + } + } + GenerateMode::Fuzz => { + if module_path.join("::") == "exports::proxy::conversion::conversion" { + self.generate_conversion_func(&sig) + } else { + self.generate_fuzz_func(module_path, &sig, &resource) + } + } + }; + methods.push(syn::ImplItem::Fn(stub_impl)); + } + _ => (), + } + } + parse_quote! { + impl #trait_path for #stub { + #(#methods)* + } + } + } + + fn generate_conversion_func(&self, sig: &Signature) -> syn::ImplItemFn { + let func_name = &sig.ident.to_string(); + let body = if func_name.starts_with("get_wrapped_") { + quote! { x.to_proxy() } + } else if func_name.starts_with("get_host_") { + quote! { x.to_proxy() } + } else if func_name.starts_with("get_mock_") { + let resource = get_return_type(&sig.output).unwrap(); + let name = func_name + .rfind("_magic42_") + .map(|idx| &func_name[idx + 9..]) + .unwrap(); + quote! { + #resource::new(MockedResource { handle, name: #name.to_string() }) + } + } else { + unreachable!() + }; + parse_quote! { + #sig { + #body + } + } + } + fn into_output_file(self) -> File { + File { + items: self.output, + shebang: None, + attrs: Vec::new(), + } + } +} + +pub fn get_proxy_path(src_path: &[String]) -> Vec { + assert!(src_path.len() >= 3); + let mut res = src_path.to_vec(); + let mut wrapped_idx = 0; + if res[0] == "exports" { + res.remove(0); + } else { + res.insert(0, "exports".to_string()); + wrapped_idx = 1; + } + match res[wrapped_idx].strip_prefix("wrapped_") { + Some(name) => res[wrapped_idx] = name.to_string(), + None => res[wrapped_idx] = "wrapped_".to_string() + &res[wrapped_idx], + } + res +} diff --git a/src/codegen/record.rs b/src/codegen/record.rs new file mode 100644 index 0000000..2671b3f --- /dev/null +++ b/src/codegen/record.rs @@ -0,0 +1,93 @@ +use super::{GenerateMode, State, get_proxy_path}; +use crate::util::{ResourceFuncKind, extract_arg_info, get_return_type, wit_func_name}; +use quote::quote; +use syn::{Signature, parse_quote}; + +impl State { + pub fn generate_instrument_func( + &self, + module_path: &[String], + sig: &Signature, + resource: &Option, + ) -> syn::ImplItemFn { + let func_name = &sig.ident; + let (kind, args) = extract_arg_info(sig); + let import_path = get_proxy_path(module_path); + let import_sig = self + .find_function(&import_path, resource, func_name) + .unwrap(); + let (_, import_args) = extract_arg_info(import_sig); + let arg_names = args.iter().map(|arg| &arg.ident); + let call_args = args + .iter() + .zip(import_args.iter()) + .map(|(arg, import_arg)| -> syn::Expr { + let ident = &arg.ident; + if import_arg.is_borrowed { + parse_quote! { &#ident } + } else { + parse_quote! { #ident } + } + }); + let (func, res): (syn::Expr, _) = match (resource.is_some(), &kind) { + (true, Some(ResourceFuncKind::Method)) => { + (parse_quote! { self.#func_name }, quote! { res.to_proxy() }) + } + (true, Some(ResourceFuncKind::Constructor)) => { + (parse_quote! { Self::#func_name }, quote! { res }) + } + (true, None) => (parse_quote! { Self::#func_name }, quote! { res.to_proxy() }), + (false, _) => ( + syn::parse_str(&format!("{}::{}", import_path.join("::"), func_name)).unwrap(), + quote! { res.to_proxy() }, + ), + }; + match &self.mode { + GenerateMode::Instrument => parse_quote! { + #sig { + let res = #func(#(#call_args.to_proxy()),*); + #res + } + }, + GenerateMode::Record => { + let init_vec = if matches!(kind, Some(ResourceFuncKind::Method)) { + quote! { vec![wasm_wave::to_string(&ToValue::to_value(&self)).unwrap()] } + } else { + quote! { Vec::new() } + }; + let is_mut = if args.is_empty() { + quote! {} + } else { + quote! { mut } + }; + let display_name = wit_func_name(module_path, resource, func_name, &kind); + let is_export = !module_path[1].starts_with("wrapped_"); + let record_ret = if get_return_type(&sig.output).is_none() { + quote! { + #func(#(#call_args),*); + proxy::recorder::record::record_ret(Some(#display_name), None, #is_export); + } + } else { + quote! { + let res = #func(#(#call_args),*); + let wave_res = wasm_wave::to_string(&res.to_value()).unwrap(); + proxy::recorder::record::record_ret(Some(#display_name), Some(&wave_res), #is_export); + #res + } + }; + parse_quote! { + #sig { + let #is_mut params: Vec = #init_vec; + #( + let #arg_names = #arg_names.to_proxy(); + params.push(wasm_wave::to_string(&ToValue::to_value(&#arg_names)).unwrap()); + )* + proxy::recorder::record::record_args(Some(#display_name), ¶ms, #is_export); + #record_ret + } + } + } + _ => unreachable!(), + } + } +} diff --git a/src/codegen/replay.rs b/src/codegen/replay.rs new file mode 100644 index 0000000..552b297 --- /dev/null +++ b/src/codegen/replay.rs @@ -0,0 +1,121 @@ +use super::State; +use crate::util::{ + FullTypePath, ResourceFuncKind, extract_arg_info, get_owned_type, get_return_type, make_path, + wit_func_name, +}; +use quote::quote; +use syn::{Signature, parse_quote, visit_mut::VisitMut}; + +impl State { + pub fn generate_replay_func( + &self, + module_path: &[String], + sig: &Signature, + resource: &Option, + ) -> syn::ImplItemFn { + let func_name = &sig.ident; + let is_export = module_path.join("::") == "exports::proxy::recorder::start_replay"; + if !is_export { + let (kind, args) = extract_arg_info(sig); + let arg_names = args.iter().map(|arg| &arg.ident); + let display_name = wit_func_name(module_path, resource, func_name, &kind); + let ret_ty = get_return_type(&sig.output); + let replay_import = if let Some(ret_ty) = ret_ty { + quote! { + let wave = proxy::recorder::replay::replay_import(Some(#display_name), Some(&args)).unwrap(); + let ret: Value = wasm_wave::from_str(&<#ret_ty as ValueTyped>::value_type(), &wave).unwrap(); + ret.to_rust() + } + } else { + quote! { + let wave = proxy::recorder::replay::replay_import(Some(#display_name), Some(&args)); + assert!(wave.is_none()); + } + }; + let self_value = if matches!(kind, Some(ResourceFuncKind::Method)) { + // Use ToValue::to_value to avoid the auto-deref from self.to_value() + quote! { wasm_wave::to_string(&ToValue::to_value(&self)).unwrap(), } + } else { + quote! {} + }; + parse_quote! { + #sig { + let args = vec![#self_value #( wasm_wave::to_string(&#arg_names.to_value()).unwrap() ),*]; + #replay_import + } + } + } else { + assert!(func_name == "start"); + let arms = self + .funcs + .iter() + .filter(|(path, _)| path[0] != "exports" && path[0] != "proxy") + .flat_map(|(path, resources)| { + resources.iter().flat_map(move |(resource, sigs)| { + sigs.iter().filter_map(move |sig| { + let (kind, args) = extract_arg_info(sig); + if matches!(kind, Some(ResourceFuncKind::Method)) { + return None; + } + let arg_name: Vec<_> = args.iter().map(|arg| &arg.ident).collect(); + let arg_idx = args.iter().enumerate().map(|(idx, _)| quote! { args[#idx] }); + let call_param = args.iter().map(|arg| arg.call_param()); + let ty = args.iter().map(|arg| { + let mut ty = arg.ty.clone(); + FullTypePath { + module_path: path, + }.visit_type_mut(&mut ty); + if let Some(owned) = get_owned_type(&ty) { + owned + } else { + ty + } + }); + let func_name = if let Some(resource) = resource { + format!("{}::{}", resource, sig.ident) + } else { + sig.ident.to_string() + }; + let func = make_path(path, &func_name); + let display_name = wit_func_name(path, resource, &sig.ident, &kind); + let assert_ret = if get_return_type(&sig.output).is_none() { + quote! { + assert!(res == ()); + proxy::recorder::replay::assert_export_ret(Some(#display_name), None); + } + } else { + quote! { + let wave_res = wasm_wave::to_string(&res.to_value()).unwrap(); + proxy::recorder::replay::assert_export_ret(Some(#display_name), Some(&wave_res)); + } + }; + Some(quote! { + #display_name => { + #( + let arg_value: Value = wasm_wave::from_str(&<#ty as ValueTyped>::value_type(), &#arg_idx).unwrap(); + let #arg_name: #ty = arg_value.to_rust(); + )* + let res = #func(#(#call_param),*); + #assert_ret + } + }) + }) + }) + }); + parse_quote! { + #sig { + while let Some((method, args)) = proxy::recorder::replay::replay_export() { + match method.as_str() { + #(#arms)* + _ => unreachable!(), + } + // clean up borrowed resources from input args + SCOPED_ALLOC.with(|alloc| { + alloc.borrow_mut().clear(); + }); + } + } + } + } + } +} From 9e1dc0b776fe0cd6b17d6006766d083ae8729303 Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Fri, 27 Feb 2026 12:53:23 -0800 Subject: [PATCH 2/6] fix --- src/codegen/mod.rs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 41fc62f..8fe8a20 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -141,6 +141,12 @@ impl State { let mut sig = method.sig.clone(); let mut transformer = FullTypePath { module_path }; transformer.visit_signature_mut(&mut sig); + let module_full_name = module_path.join("::"); + if module_full_name == "exports::proxy::conversion::conversion" { + let stub_impl = self.generate_conversion_func(&sig); + methods.push(syn::ImplItem::Fn(stub_impl)); + continue; + } let stub_impl = match self.mode { GenerateMode::Stubs => parse_quote! { #[allow(unused_variables)] @@ -149,26 +155,12 @@ impl State { } }, GenerateMode::Instrument | GenerateMode::Record => { - if module_path.join("::") == "exports::proxy::conversion::conversion" { - self.generate_conversion_func(&sig) - } else { - self.generate_instrument_func(module_path, &sig, &resource) - } + self.generate_instrument_func(module_path, &sig, &resource) } GenerateMode::Replay => { - if module_path.join("::") == "exports::proxy::conversion::conversion" { - self.generate_conversion_func(&sig) - } else { - self.generate_replay_func(module_path, &sig, &resource) - } - } - GenerateMode::Fuzz => { - if module_path.join("::") == "exports::proxy::conversion::conversion" { - self.generate_conversion_func(&sig) - } else { - self.generate_fuzz_func(module_path, &sig, &resource) - } + self.generate_replay_func(module_path, &sig, &resource) } + GenerateMode::Fuzz => self.generate_fuzz_func(module_path, &sig, &resource), }; methods.push(syn::ImplItem::Fn(stub_impl)); } From 3bd39464aa7595561dee2ea87fb764a8c56c2a98 Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Fri, 27 Feb 2026 17:17:02 -0800 Subject: [PATCH 3/6] run trace crate --- Cargo.lock | 12 ++++- Cargo.toml | 10 ++-- components/recorder/Cargo.toml | 4 +- components/recorder/src/lib.rs | 28 ++-------- crates/trace/Cargo.toml | 8 +++ .../src/trace.rs => crates/trace/src/lib.rs | 34 ++++++++++++ src/run.rs | 52 ++----------------- 7 files changed, 66 insertions(+), 82 deletions(-) create mode 100644 crates/trace/Cargo.toml rename components/recorder/src/trace.rs => crates/trace/src/lib.rs (51%) diff --git a/Cargo.lock b/Cargo.lock index bdf6e12..ebe3562 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1323,10 +1323,10 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "serde", "serde_json", "syn", "tempfile", + "trace", "wasmtime", "wasmtime-wasi", "wit-bindgen-core", @@ -1434,8 +1434,8 @@ dependencies = [ name = "recorder" version = "0.1.0" dependencies = [ - "serde", "serde_json", + "trace", "wit-bindgen 0.52.0", ] @@ -1838,6 +1838,14 @@ version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +[[package]] +name = "trace" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tracing" version = "0.1.41" diff --git a/Cargo.toml b/Cargo.toml index 4e6b25c..e0691ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,9 +2,11 @@ members = [ "components/debug", "components/recorder" -] +, "crates/trace"] [workspace.dependencies] wit-bindgen = { version = "0.52.0", default-features = false, features = ["bitflags", "std", "macros"] } +serde = { version = "1.0.226", features = ["derive"] } +serde_json = "1.0.145" [package] name = "proxy-component" @@ -12,18 +14,16 @@ version = "0.1.0" edition = "2024" [dependencies] +trace = { path = "crates/trace" } anyhow = "1.0.98" clap = { version = "4.5.40", features = ["derive"] } heck = "0.5.0" prettyplease = "0.2.37" quote = "1.0.41" proc-macro2 = "1.0.103" -serde = "1.0.226" -serde_json = "1.0.145" +serde_json.workspace = true syn = { version = "2.0.108", features = ["visit-mut"] } tempfile = "3.20.0" -#wit-bindgen-core = { git = "https://github.com/chenyan2002/wit-bindgen.git", branch = "proxy" } -#wit-bindgen-rust = { git = "https://github.com/chenyan2002/wit-bindgen.git", branch = "proxy" } wit-bindgen-core = "0.52.0" wit-component = "0.244.0" diff --git a/components/recorder/Cargo.toml b/components/recorder/Cargo.toml index 0ba2fb8..e64a57a 100644 --- a/components/recorder/Cargo.toml +++ b/components/recorder/Cargo.toml @@ -7,6 +7,6 @@ edition = "2024" crate-type = ["cdylib"] [dependencies] +trace = { path = "../../crates/trace" } +serde_json.workspace = true wit-bindgen.workspace = true -serde = { version = "1.0.226", features = ["derive"] } -serde_json = "1.0.145" diff --git a/components/recorder/src/lib.rs b/components/recorder/src/lib.rs index 1ac37aa..95e985c 100644 --- a/components/recorder/src/lib.rs +++ b/components/recorder/src/lib.rs @@ -4,29 +4,17 @@ mod bindings { world: "guest", }); } -mod trace; use trace::FuncCall; struct Component; impl bindings::exports::proxy::recorder::record::Guest for Component { fn record_args(method: Option, args: Vec, is_export: bool) { - let call = if is_export { - FuncCall::ExportArgs { - method: method.unwrap(), - args, - } - } else { - FuncCall::ImportArgs { method, args } - }; + let call = trace::record_args(method, args, is_export); let json = serde_json::to_string(&call).unwrap(); println!("{json}"); } fn record_ret(method: Option, ret: Option, is_export: bool) { - let call = if is_export { - FuncCall::ExportRet { method, ret } - } else { - FuncCall::ImportRet { method, ret } - }; + let call = trace::record_ret(method, ret, is_export); let json = serde_json::to_string(&call).unwrap(); println!("{json}"); } @@ -42,18 +30,10 @@ fn load_trace() { let load = TRACE.with_borrow(|v| v.is_none()); if load { TRACE.with_borrow_mut(|v| { - use std::io::BufRead; - let mut res = VecDeque::new(); let f = std::io::stdin(); let reader = std::io::BufReader::new(f); - for line in reader.lines() { - let line = line.unwrap(); - match serde_json::from_str::(&line) { - Ok(item) => res.push_back(item), - Err(_) => continue, - } - } - *v = Some(res); + let res = trace::load_trace(reader); + *v = Some(res.into_iter().collect()); }); } } diff --git a/crates/trace/Cargo.toml b/crates/trace/Cargo.toml new file mode 100644 index 0000000..fb4614b --- /dev/null +++ b/crates/trace/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "trace" +version = "0.1.0" +edition = "2024" + +[dependencies] +serde.workspace = true +serde_json.workspace = true diff --git a/components/recorder/src/trace.rs b/crates/trace/src/lib.rs similarity index 51% rename from components/recorder/src/trace.rs rename to crates/trace/src/lib.rs index 14aeb8e..92c8ce9 100644 --- a/components/recorder/src/trace.rs +++ b/crates/trace/src/lib.rs @@ -19,6 +19,40 @@ pub enum FuncCall { ret: Option, }, } + +pub fn load_trace(reader: impl std::io::BufRead) -> Vec { + let mut res = Vec::new(); + for line in reader.lines() { + let line = line.unwrap(); + match serde_json::from_str::(&line) { + Ok(item) => res.push(item), + // Ignore non-JSON lines. + Err(_) => continue, + } + } + res +} + +pub fn record_args(method: Option, args: Vec, is_export: bool) -> FuncCall { + let call = if is_export { + FuncCall::ExportArgs { + method: method.unwrap(), + args, + } + } else { + FuncCall::ImportArgs { method, args } + }; + call +} +pub fn record_ret(method: Option, ret: Option, is_export: bool) -> FuncCall { + let call = if is_export { + FuncCall::ExportRet { method, ret } + } else { + FuncCall::ImportRet { method, ret } + }; + call +} + impl FuncCall { pub fn to_string(&self) -> String { match self { diff --git a/src/run.rs b/src/run.rs index e60e780..7860f60 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,7 +1,7 @@ use clap::Parser; -use serde::{Deserialize, Serialize}; use std::collections::VecDeque; use std::path::PathBuf; +use trace::FuncCall; use wasmtime::component::types::{ComponentFunc, ComponentItem as CItem}; use wasmtime::component::wasm_wave::{untyped::UntypedFuncCall, wasm::WasmFunc}; use wasmtime::component::{Component, HasSelf, Linker, ResourceTable, Val}; @@ -27,41 +27,6 @@ mod bindings { }); } -#[derive(Serialize, Deserialize, Debug)] -enum FuncCall { - ExportArgs { - method: String, - args: Vec, - }, - ExportRet { - method: Option, - ret: Option, - }, - ImportArgs { - method: Option, - args: Vec, - }, - ImportRet { - method: Option, - ret: Option, - }, -} -impl FuncCall { - fn to_string(&self) -> String { - match self { - FuncCall::ExportArgs { method, args } => format!("{method}({})", args.join(", ")), - FuncCall::ImportArgs { method, args } => format!( - "{}({})", - method.as_deref().unwrap_or(""), - args.join(", ") - ), - FuncCall::ExportRet { ret, .. } | FuncCall::ImportRet { ret, .. } => { - ret.as_deref().unwrap_or("()").to_owned() - } - } - } -} - struct Logger { wasi_ctx: WasiCtx, resource_table: ResourceTable, @@ -70,23 +35,12 @@ struct Logger { } impl bindings::proxy::recorder::record::Host for Logger { fn record_args(&mut self, method: Option, args: Vec, is_export: bool) { - let call = if is_export { - FuncCall::ExportArgs { - method: method.unwrap(), - args, - } - } else { - FuncCall::ImportArgs { method, args } - }; + let call = trace::record_args(method, args, is_export); println!("call: {}", call.to_string()); self.logger.push_back(call); } fn record_ret(&mut self, method: Option, ret: Option, is_export: bool) { - let call = if is_export { - FuncCall::ExportRet { method, ret } - } else { - FuncCall::ImportRet { method, ret } - }; + let call = trace::record_ret(method, ret, is_export); println!("ret: {}", call.to_string()); self.logger.push_back(call); } From dd9e3e45aaa51a63c4c49e10d4e6c163a4543859 Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Fri, 27 Feb 2026 18:35:17 -0800 Subject: [PATCH 4/6] move record logic into the crate --- Cargo.lock | 1 - Cargo.toml | 1 - assets/recorder.wasm | Bin 233196 -> 237642 bytes components/recorder/src/lib.rs | 76 +++++------------ crates/trace/src/lib.rs | 146 ++++++++++++++++++++++++++------- src/run.rs | 81 ++++++------------ 6 files changed, 160 insertions(+), 145 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebe3562..7d02b46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1323,7 +1323,6 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "serde_json", "syn", "tempfile", "trace", diff --git a/Cargo.toml b/Cargo.toml index e0691ff..72fdef2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ heck = "0.5.0" prettyplease = "0.2.37" quote = "1.0.41" proc-macro2 = "1.0.103" -serde_json.workspace = true syn = { version = "2.0.108", features = ["visit-mut"] } tempfile = "3.20.0" wit-bindgen-core = "0.52.0" diff --git a/assets/recorder.wasm b/assets/recorder.wasm index 1c121f2b06d359ceb19bc192f56eba45d8473bcd..dbd56cd58723b64b0dc89f2e9ea6a545bee2cee2 100644 GIT binary patch delta 59432 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 delta 56017 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, args: Vec, is_export: bool) { - let call = trace::record_args(method, args, is_export); + let mut logger = Logger::new(); + let call = logger.record_args(method, args, is_export); let json = serde_json::to_string(&call).unwrap(); println!("{json}"); } fn record_ret(method: Option, ret: Option, is_export: bool) { - let call = trace::record_ret(method, ret, is_export); + let mut logger = Logger::new(); + let call = logger.record_ret(method, ret, is_export); let json = serde_json::to_string(&call).unwrap(); println!("{json}"); } } use std::cell::RefCell; -use std::collections::VecDeque; thread_local! { - static TRACE: RefCell>> = RefCell::new(None); + static TRACE: RefCell> = RefCell::new(None); } fn load_trace() { let load = TRACE.with_borrow(|v| v.is_none()); if load { TRACE.with_borrow_mut(|v| { - let f = std::io::stdin(); - let reader = std::io::BufReader::new(f); - let res = trace::load_trace(reader); - *v = Some(res.into_iter().collect()); + use std::io::Read; + let mut input = String::new(); + std::io::stdin().read_to_string(&mut input).unwrap(); + let mut logger = Logger::new(); + logger.load_trace(&input); + *v = Some(logger); }); } } @@ -41,28 +44,13 @@ fn load_trace() { impl bindings::exports::proxy::recorder::replay::Guest for Component { fn replay_export() -> Option<(String, Vec)> { load_trace(); - TRACE.with_borrow_mut(|v| { - let call = v.as_mut().unwrap().pop_front()?; - println!("export call: {}", call.to_string()); - let FuncCall::ExportArgs { method, args } = call else { - panic!() - }; - Some((method, args)) - }) + TRACE.with_borrow_mut(|v| v.as_mut().unwrap().replay_export()) } fn assert_export_ret(assert_method: Option, assert_ret: Option) { TRACE.with_borrow_mut(|v| { - if let Some(FuncCall::ExportRet { .. }) = v.as_mut().unwrap().front() { - let call = v.as_mut().unwrap().pop_front().unwrap(); - println!("export ret: {}", call.to_string()); - let FuncCall::ExportRet { method, ret } = call else { - panic!() - }; - if let (Some(method), Some(assert_method)) = (method, assert_method) { - assert_eq!(method, assert_method); - } - assert_eq!(ret, assert_ret); - } + v.as_mut() + .unwrap() + .assert_export_ret(assert_method, assert_ret) }); } fn replay_import( @@ -70,34 +58,10 @@ impl bindings::exports::proxy::recorder::replay::Guest for Component { assert_args: Option>, ) -> Option { TRACE.with_borrow_mut(|v| { - let mut call = v.as_mut().unwrap().pop_front().unwrap(); - if let FuncCall::ImportArgs { method, args } = &call { - if let (Some(method), Some(assert_method)) = (method, assert_method) { - assert_eq!(method, &assert_method); - } - if let Some(assert_args) = &assert_args { - assert_eq!(args, assert_args); - } - println!("import call: {}", call.to_string()); - if method - .as_ref() - .is_some_and(|m| m.starts_with("wasi:cli/exit")) - { - let code = if assert_args - .is_some_and(|args| args.get(0).is_some_and(|arg| arg.starts_with("err"))) - { - 1 - } else { - 0 - }; - std::process::exit(code); - } - call = v.as_mut().unwrap().pop_front().unwrap(); - } - println!("import ret: {}", call.to_string()); - let FuncCall::ImportRet { ret, .. } = call else { - panic!() - }; + let (_, ret) = v + .as_mut() + .unwrap() + .replay_import(assert_method, assert_args, true); ret }) } diff --git a/crates/trace/src/lib.rs b/crates/trace/src/lib.rs index 92c8ce9..e263552 100644 --- a/crates/trace/src/lib.rs +++ b/crates/trace/src/lib.rs @@ -1,6 +1,8 @@ +use std::collections::VecDeque; + use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub enum FuncCall { ExportArgs { method: String, @@ -20,37 +22,123 @@ pub enum FuncCall { }, } -pub fn load_trace(reader: impl std::io::BufRead) -> Vec { - let mut res = Vec::new(); - for line in reader.lines() { - let line = line.unwrap(); - match serde_json::from_str::(&line) { - Ok(item) => res.push(item), - // Ignore non-JSON lines. - Err(_) => continue, +pub struct Logger(pub VecDeque); + +impl Logger { + pub fn new() -> Self { + Self(VecDeque::new()) + } + pub fn load_trace(&mut self, text: &str) { + self.0.clear(); + for line in text.lines() { + match serde_json::from_str::(line) { + Ok(item) => self.0.push_back(item), + // Ignore non-JSON lines. + Err(_) => continue, + } } } - res -} - -pub fn record_args(method: Option, args: Vec, is_export: bool) -> FuncCall { - let call = if is_export { - FuncCall::ExportArgs { - method: method.unwrap(), - args, + pub fn dump_trace(&self) -> String { + self.0 + .iter() + .map(|call| serde_json::to_string(call).unwrap()) + .collect::>() + .join("\n") + } + pub fn record_args( + &mut self, + method: Option, + args: Vec, + is_export: bool, + ) -> FuncCall { + let call = if is_export { + FuncCall::ExportArgs { + method: method.unwrap(), + args, + } + } else { + FuncCall::ImportArgs { method, args } + }; + self.0.push_back(call.clone()); + call + } + pub fn record_ret( + &mut self, + method: Option, + ret: Option, + is_export: bool, + ) -> FuncCall { + let call = if is_export { + FuncCall::ExportRet { method, ret } + } else { + FuncCall::ImportRet { method, ret } + }; + self.0.push_back(call.clone()); + call + } + pub fn replay_export(&mut self) -> Option<(String, Vec)> { + let call = self.0.pop_front()?; + println!("export call: {}", call.to_string()); + let FuncCall::ExportArgs { method, args } = call else { + panic!() + }; + Some((method, args)) + } + pub fn assert_export_ret(&mut self, assert_method: Option, assert_ret: Option) { + if let Some(FuncCall::ExportRet { .. }) = self.0.front() { + let call = self.0.pop_front().unwrap(); + println!("export ret: {}", call.to_string()); + let FuncCall::ExportRet { method, ret } = call else { + panic!() + }; + if let (Some(method), Some(assert_method)) = (method, assert_method) { + assert_eq!(method, assert_method); + } + assert_eq!(ret, assert_ret); } - } else { - FuncCall::ImportArgs { method, args } - }; - call -} -pub fn record_ret(method: Option, ret: Option, is_export: bool) -> FuncCall { - let call = if is_export { - FuncCall::ExportRet { method, ret } - } else { - FuncCall::ImportRet { method, ret } - }; - call + } + pub fn replay_import( + &mut self, + assert_method: Option, + assert_args: Option>, + from_guest: bool, + ) -> (bool, Option) { + let mut exit_called = false; + let mut call = self.0.pop_front().unwrap(); + if let FuncCall::ImportArgs { method, args } = &call { + if let (Some(method), Some(assert_method)) = (method, assert_method) { + assert_eq!(method, &assert_method); + } + if let Some(assert_args) = &assert_args { + assert_eq!(args, assert_args); + } + println!("import call: {}", call.to_string()); + if method + .as_ref() + .is_some_and(|m| m.starts_with("wasi:cli/exit")) + { + if from_guest { + let code = if assert_args + .is_some_and(|args| args.get(0).is_some_and(|arg| arg.starts_with("err"))) + { + 1 + } else { + 0 + }; + std::process::exit(code); + } else { + exit_called = true; + return (exit_called, Some("Something that can crash".to_string())); + } + } + call = self.0.pop_front().unwrap(); + } + println!("import ret: {}", call.to_string()); + let FuncCall::ImportRet { ret, .. } = call else { + panic!() + }; + (exit_called, ret) + } } impl FuncCall { diff --git a/src/run.rs b/src/run.rs index 7860f60..123cdc0 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,7 +1,6 @@ use clap::Parser; -use std::collections::VecDeque; use std::path::PathBuf; -use trace::FuncCall; +use trace::Logger; use wasmtime::component::types::{ComponentFunc, ComponentItem as CItem}; use wasmtime::component::wasm_wave::{untyped::UntypedFuncCall, wasm::WasmFunc}; use wasmtime::component::{Component, HasSelf, Linker, ResourceTable, Val}; @@ -27,73 +26,39 @@ mod bindings { }); } -struct Logger { +struct State { wasi_ctx: WasiCtx, resource_table: ResourceTable, - logger: VecDeque, + logger: Logger, exit_called: bool, } -impl bindings::proxy::recorder::record::Host for Logger { +impl bindings::proxy::recorder::record::Host for State { fn record_args(&mut self, method: Option, args: Vec, is_export: bool) { - let call = trace::record_args(method, args, is_export); + let call = self.logger.record_args(method, args, is_export); println!("call: {}", call.to_string()); - self.logger.push_back(call); } fn record_ret(&mut self, method: Option, ret: Option, is_export: bool) { - let call = trace::record_ret(method, ret, is_export); + let call = self.logger.record_ret(method, ret, is_export); println!("ret: {}", call.to_string()); - self.logger.push_back(call); } } -impl bindings::proxy::recorder::replay::Host for Logger { +impl bindings::proxy::recorder::replay::Host for State { fn replay_export(&mut self) -> Option<(String, Vec)> { - let call = self.logger.pop_front()?; - println!("export call: {}", call.to_string()); - let FuncCall::ExportArgs { method, args } = call else { - panic!() - }; - Some((method, args)) + self.logger.replay_export() } fn assert_export_ret(&mut self, assert_method: Option, assert_ret: Option) { - if let Some(FuncCall::ExportRet { .. }) = self.logger.front() { - let call = self.logger.pop_front().unwrap(); - println!("export ret: {}", call.to_string()); - let FuncCall::ExportRet { method, ret } = call else { - panic!() - }; - if let (Some(method), Some(assert_method)) = (method, assert_method) { - assert_eq!(method, assert_method); - } - assert_eq!(ret, assert_ret); - } + self.logger.assert_export_ret(assert_method, assert_ret); } fn replay_import( &mut self, assert_method: Option, assert_args: Option>, ) -> Option { - let mut call = self.logger.pop_front().unwrap(); - if let FuncCall::ImportArgs { method, args } = &call { - if let (Some(method), Some(assert_method)) = (method, assert_method) { - assert_eq!(method, &assert_method); - } - if let Some(assert_args) = &assert_args { - assert_eq!(args, assert_args); - } - println!("import call: {}", call.to_string()); - if method - .as_ref() - .is_some_and(|m| m.starts_with("wasi:cli/exit")) - { - self.exit_called = true; - return Some("Something that can crash".to_string()); - } - call = self.logger.pop_front().unwrap(); + let (exit_called, ret) = self.logger.replay_import(assert_method, assert_args, false); + if exit_called { + self.exit_called = exit_called; + return Some("Something that can crash".to_string()); } - println!("import ret: {}", call.to_string()); - let FuncCall::ImportRet { ret, .. } = call else { - panic!() - }; ret } } @@ -108,25 +73,25 @@ pub fn run(args: RunArgs) -> anyhow::Result<()> { .wasm_backtrace_details(WasmBacktraceDetails::Enable); let engine = Engine::new(&config)?; - let mut linker = Linker::::new(&engine); + let mut linker = Linker::::new(&engine); add_to_linker_sync(&mut linker)?; let wasi = WasiCtxBuilder::new().inherit_stdio().inherit_args().build(); - let mut state = Logger { + let mut state = State { wasi_ctx: wasi, resource_table: ResourceTable::new(), - logger: VecDeque::new(), + logger: Logger::new(), exit_called: false, }; if let Some(path) = &args.trace { - bindings::proxy::recorder::replay::add_to_linker::<_, HasSelf<_>>(&mut linker, |logger| { - logger + bindings::proxy::recorder::replay::add_to_linker::<_, HasSelf<_>>(&mut linker, |state| { + state })?; let trace = std::fs::read_to_string(path)?; - state.logger = serde_json::from_str(&trace)?; + state.logger.load_trace(&trace); } else { - bindings::proxy::recorder::record::add_to_linker::>( + bindings::proxy::recorder::record::add_to_linker::>( &mut linker, - |logger| logger, + |state| state, )?; } @@ -165,7 +130,7 @@ pub fn run(args: RunArgs) -> anyhow::Result<()> { } }?; if args.trace.is_none() { - let trace = serde_json::to_string(&store.data().logger)?; + let trace = store.data().logger.dump_trace(); std::fs::write("trace.out", &trace)?; } } @@ -218,7 +183,7 @@ fn collect_export_funcs( .collect() } -impl WasiView for Logger { +impl WasiView for State { fn ctx(&mut self) -> WasiCtxView<'_> { WasiCtxView { ctx: &mut self.wasi_ctx, From 364e54cd62632edc7afa97c7b78fe6037d11bbe1 Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Fri, 27 Feb 2026 18:56:32 -0800 Subject: [PATCH 5/6] test host replay --- Cargo.lock | 755 ++++++++++++++++++++++++------------------- Cargo.toml | 8 +- Makefile | 17 +- assets/debug.wasm | Bin 92827 -> 92827 bytes assets/recorder.wasm | Bin 237642 -> 237715 bytes 5 files changed, 438 insertions(+), 342 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d02b46..06e6124 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addr2line" -version = "0.25.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +checksum = "9698bf0769c641b18618039fe2ebd41eb3541f98433000f64e663fab7cea2c87" dependencies = [ "gimli", ] @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "arbitrary" @@ -119,9 +119,9 @@ checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitmaps" @@ -143,18 +143,18 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" dependencies = [ "allocator-api2", ] [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cap-fs-ext" @@ -176,7 +176,7 @@ checksum = "20a158160765c6a7d0d8c072a53d772e4cb243f38b04bfcf6b4939cfbe7482e7" dependencies = [ "cap-primitives", "cap-std", - "rustix 1.1.2", + "rustix 1.1.4", "smallvec", ] @@ -192,7 +192,7 @@ dependencies = [ "io-lifetimes", "ipnet", "maybe-owned", - "rustix 1.1.2", + "rustix 1.1.4", "rustix-linux-procfs", "windows-sys 0.59.0", "winx", @@ -217,7 +217,7 @@ dependencies = [ "cap-primitives", "io-extras", "io-lifetimes", - "rustix 1.1.2", + "rustix 1.1.4", ] [[package]] @@ -230,15 +230,15 @@ dependencies = [ "cap-primitives", "iana-time-zone", "once_cell", - "rustix 1.1.2", + "rustix 1.1.4", "winx", ] [[package]] name = "cc" -version = "1.2.46" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "jobserver", @@ -254,9 +254,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.52" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa8120877db0e5c011242f96806ce3c94e0737ab8108532a76a3300a01db2ab8" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -264,9 +264,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.52" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02576b399397b659c26064fbc92a75fede9d18ffd5f80ca1cd74ddab167016e1" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstream", "anstyle", @@ -276,9 +276,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", @@ -288,9 +288,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "cobs" @@ -298,7 +298,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -333,46 +333,47 @@ dependencies = [ [[package]] name = "cranelift-assembler-x64" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0377b13bf002a0774fcccac4f1102a10f04893d24060cf4b7350c87e4cbb647c" +checksum = "40630d663279bc855bff805d6f5e8a0b6a1867f9df95b010511ac6dc894e9395" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa027979140d023b25bf7509fb7ede3a54c3d3871fb5ead4673c4b633f671a2" +checksum = "3ee6aec5ceb55e5fdbcf7ef677d7c7195531360ff181ce39b2b31df11d57305f" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618e4da87d9179a70b3c2f664451ca8898987aa6eb9f487d16988588b5d8cc40" +checksum = "9a92d78cc3f087d7e7073828f08d98c7074a3a062b6b29a1b7783ce74305685e" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db53764b5dad233b37b8f5dc54d3caa9900c54579195e00f17ea21f03f71aaa7" +checksum = "edcc73d756f2e0d7eda6144fe64a2bc69c624de893cb1be51f1442aed77881d2" dependencies = [ "serde", "serde_derive", + "wasmtime-internal-core", ] [[package]] name = "cranelift-codegen" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae927f1d8c0abddaa863acd201471d56e7fc6c3925104f4861ed4dc3e28b421" +checksum = "683d94c2cd0d73b41369b88da1129589bc3a2d99cf49979af1d14751f35b7a1b" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -385,6 +386,7 @@ dependencies = [ "cranelift-isle", "gimli", "hashbrown 0.15.5", + "libm", "log", "pulley-interpreter", "regalloc2", @@ -392,14 +394,14 @@ dependencies = [ "serde", "smallvec", "target-lexicon", - "wasmtime-internal-math", + "wasmtime-internal-core", ] [[package]] name = "cranelift-codegen-meta" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fcf1e3e6757834bd2584f4cbff023fcc198e9279dcb5d684b4bb27a9b19f54" +checksum = "235da0e52ee3a0052d0e944c3470ff025b1f4234f6ec4089d3109f2d2ffa6cbd" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -410,35 +412,36 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "205dcb9e6ccf9d368b7466be675ff6ee54a63e36da6fe20e72d45169cf6fd254" +checksum = "20c07c6c440bd1bf920ff7597a1e743ede1f68dcd400730bd6d389effa7662af" [[package]] name = "cranelift-control" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "108eca9fcfe86026054f931eceaf57b722c1b97464bf8265323a9b5877238817" +checksum = "8797c022e02521901e1aee483dea3ed3c67f2bf0a26405c9dd48e8ee7a70944b" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d96496910065d3165f84ff8e1e393916f4c086f88ac8e1b407678bc78735aa" +checksum = "59d8e72637246edd2cba337939850caa8b201f6315925ec4c156fdd089999699" dependencies = [ "cranelift-bitset", "serde", "serde_derive", + "wasmtime-internal-core", ] [[package]] name = "cranelift-frontend" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e303983ad7e23c850f24d9c41fc3cb346e1b930f066d3966545e4c98dac5c9fb" +checksum = "4c31db0085c3dfa131e739c3b26f9f9c84d69a9459627aac1ac4ef8355e3411b" dependencies = [ "cranelift-codegen", "log", @@ -448,15 +451,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b0cf8d867d891245836cac7abafb0a5b0ea040a019d720702b3b8bcba40bfa" +checksum = "524d804c1ebd8c542e6f64e71aa36934cec17c5da4a9ae3799796220317f5d23" [[package]] name = "cranelift-native" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24b641e315443e27807b69c440fe766737d7e718c68beb665a2d69259c77bf3" +checksum = "dc9598f02540e382e1772416eba18e93c5275b746adbbf06ac1f3cf149415270" dependencies = [ "cranelift-codegen", "libc", @@ -465,9 +468,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.128.3" +version = "0.129.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e378a54e7168a689486d67ee1f818b7e5356e54ae51a1d7a53f4f13f7f8b7a" +checksum = "d953932541249c91e3fa70a75ff1e52adc62979a2a8132145d4b9b3e6d1a9b6a" [[package]] name = "crc32fast" @@ -615,12 +618,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - [[package]] name = "fastrand" version = "2.3.0" @@ -634,15 +631,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix 1.1.2", + "rustix 1.1.4", "windows-sys 0.59.0", ] [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fixedbitset" @@ -662,6 +659,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -678,15 +681,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" dependencies = [ "io-lifetimes", - "rustix 1.1.2", + "rustix 1.1.4", "windows-sys 0.59.0", ] [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -698,9 +701,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -708,33 +711,33 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -743,7 +746,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -773,9 +775,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", @@ -794,13 +796,27 @@ dependencies = [ "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "gimli" -version = "0.32.3" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" dependencies = [ - "fallible-iterator", + "fnv", + "hashbrown 0.16.1", "indexmap", "stable_deref_trait", ] @@ -811,7 +827,7 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash", + "foldhash 0.1.5", "serde", ] @@ -820,6 +836,9 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash 0.2.0", +] [[package]] name = "heck" @@ -829,9 +848,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -899,9 +918,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -913,9 +932,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" @@ -934,9 +953,9 @@ dependencies = [ [[package]] name = "id-arena" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] name = "idna" @@ -1024,9 +1043,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "ittapi" @@ -1060,9 +1079,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.82" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -1088,21 +1107,21 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags", "libc", @@ -1116,9 +1135,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -1128,9 +1147,9 @@ checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "logos" @@ -1182,9 +1201,9 @@ checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memfd" @@ -1192,14 +1211,14 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" dependencies = [ - "rustix 1.1.2", + "rustix 1.1.4", ] [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", @@ -1248,15 +1267,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" @@ -1306,9 +1319,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1328,27 +1341,27 @@ dependencies = [ "trace", "wasmtime", "wasmtime-wasi", - "wit-bindgen-core", - "wit-component", + "wit-bindgen-core 0.53.1", + "wit-component 0.245.1", ] [[package]] name = "pulley-interpreter" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01051a5b172e07f9197b85060e6583b942aec679dac08416647bf7e7dc916b65" +checksum = "bc2d61e068654529dc196437f8df0981db93687fdc67dec6a5de92363120b9da" dependencies = [ "cranelift-bitset", "log", "pulley-macros", - "wasmtime-internal-math", + "wasmtime-internal-core", ] [[package]] name = "pulley-macros" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf194f5b1a415ef3a44ee35056f4009092cc4038a9f7e3c7c1e392f48ee7dbb" +checksum = "c3f210c61b6ecfaebbba806b6d9113a222519d4e5cc4ab2d5ecca047bb7927ae" dependencies = [ "proc-macro2", "quote", @@ -1357,9 +1370,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.42" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -1397,7 +1410,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] @@ -1444,16 +1457,16 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", "thiserror 1.0.69", ] [[package]] name = "regalloc2" -version = "0.13.3" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e249c660440317032a71ddac302f25f1d5dff387667bcc3978d1f77aa31ac34" +checksum = "08effbc1fa53aaebff69521a5c05640523fab037b34a4a2c109506bc938246fa" dependencies = [ "allocator-api2", "bumpalo", @@ -1465,15 +1478,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rustc-demangle" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" @@ -1496,14 +1509,14 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.11.0", + "linux-raw-sys 0.12.1", "windows-sys 0.61.2", ] @@ -1514,7 +1527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" dependencies = [ "once_cell", - "rustix 1.1.2", + "rustix 1.1.4", ] [[package]] @@ -1525,9 +1538,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "semver" @@ -1571,15 +1584,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -1648,9 +1661,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -1670,9 +1683,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.110" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1708,20 +1721,20 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.3" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "tempfile" -version = "3.23.0" +version = "3.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.1", "once_cell", - "rustix 1.1.2", + "rustix 1.1.4", "windows-sys 0.61.2", ] @@ -1745,11 +1758,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -1765,9 +1778,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -1786,9 +1799,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "bytes", "libc", @@ -1824,9 +1837,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.7+spec-1.1.0" +version = "1.0.9+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ "winnow", ] @@ -1847,9 +1860,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -1858,9 +1871,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -1869,9 +1882,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] @@ -1884,9 +1897,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-width" @@ -1908,9 +1921,9 @@ checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -1932,9 +1945,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.18.1" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" dependencies = [ "js-sys", "wasm-bindgen", @@ -1954,18 +1967,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen 0.46.0", + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -1976,9 +1998,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1986,9 +2008,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", @@ -1999,18 +2021,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-compose" -version = "0.243.0" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af801b6f36459023eaec63fdbaedad2fd5a4ab7dc74ecc110a8b5d375c5775e4" +checksum = "92cda9c76ca8dcac01a8b497860c2cb15cd6f216dc07060517df5abbe82512ac" dependencies = [ "anyhow", "heck", @@ -2022,21 +2044,11 @@ dependencies = [ "serde_derive", "serde_yaml", "smallvec", - "wasm-encoder 0.243.0", - "wasmparser 0.243.0", + "wasm-encoder 0.244.0", + "wasmparser 0.244.0", "wat", ] -[[package]] -name = "wasm-encoder" -version = "0.243.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35" -dependencies = [ - "leb128fmt", - "wasmparser 0.243.0", -] - [[package]] name = "wasm-encoder" version = "0.244.0" @@ -2049,12 +2061,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.245.0" +version = "0.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95d568e113f706ee7a7df9b33547bb80721f55abffc79b3dc4d09c368690e662" +checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c" dependencies = [ "leb128fmt", - "wasmparser 0.245.0", + "wasmparser 0.245.1", ] [[package]] @@ -2070,28 +2082,26 @@ dependencies = [ ] [[package]] -name = "wasm-wave" -version = "0.243.0" +name = "wasm-metadata" +version = "0.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd23c879ec35d708f4eff3456f33c415d113363a2e38420098bf42976bacb31" +checksum = "da55e60097e8b37b475a0fa35c3420dd71d9eb7bd66109978ab55faf56a57efb" dependencies = [ + "anyhow", "indexmap", - "logos", - "thiserror 2.0.17", - "wit-parser 0.243.0", + "wasm-encoder 0.245.1", + "wasmparser 0.245.1", ] [[package]] -name = "wasmparser" -version = "0.243.0" +name = "wasm-wave" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" +checksum = "d1c34a4c10a1b9260f8131929d680e36edf00836bb8e76524d3004522bd6f287" dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", - "serde", + "logos", + "thiserror 2.0.18", + "wit-parser 0.244.0", ] [[package]] @@ -2104,38 +2114,39 @@ dependencies = [ "hashbrown 0.15.5", "indexmap", "semver", + "serde", ] [[package]] name = "wasmparser" -version = "0.245.0" +version = "0.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48a767a48974f0c8b66f211b96e01aa77feed58b8ccce4e7f0cff0ae55b174d4" +checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" dependencies = [ "bitflags", + "hashbrown 0.16.1", "indexmap", "semver", ] [[package]] name = "wasmprinter" -version = "0.243.0" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2b6035559e146114c29a909a3232928ee488d6507a1504d8934e8607b36d7b" +checksum = "09390d7b2bd7b938e563e4bff10aa345ef2e27a3bc99135697514ef54495e68f" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.243.0", + "wasmparser 0.244.0", ] [[package]] name = "wasmtime" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19f56cece843fa95dd929f5568ff8739c7e3873b530ceea9eda2aa02a0b4142" +checksum = "39bef52be4fb4c5b47d36f847172e896bc94b35c9c6a6f07117686bd16ed89a7" dependencies = [ "addr2line", - "anyhow", "async-trait", "bitflags", "bumpalo", @@ -2145,8 +2156,6 @@ dependencies = [ "futures", "fxprof-processed-profile", "gimli", - "hashbrown 0.15.5", - "indexmap", "ittapi", "libc", "log", @@ -2157,7 +2166,7 @@ dependencies = [ "postcard", "pulley-interpreter", "rayon", - "rustix 1.1.2", + "rustix 1.1.4", "semver", "serde", "serde_derive", @@ -2166,19 +2175,18 @@ dependencies = [ "target-lexicon", "tempfile", "wasm-compose", - "wasm-encoder 0.243.0", + "wasm-encoder 0.244.0", "wasm-wave", - "wasmparser 0.243.0", + "wasmparser 0.244.0", "wasmtime-environ", "wasmtime-internal-cache", "wasmtime-internal-component-macro", "wasmtime-internal-component-util", + "wasmtime-internal-core", "wasmtime-internal-cranelift", "wasmtime-internal-fiber", "wasmtime-internal-jit-debug", "wasmtime-internal-jit-icache-coherence", - "wasmtime-internal-math", - "wasmtime-internal-slab", "wasmtime-internal-unwinder", "wasmtime-internal-versioned-export-macros", "wasmtime-internal-winch", @@ -2188,15 +2196,16 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf9dff572c950258548cbbaf39033f68f8dcd0b43b22e80def9fe12d532d3e5" +checksum = "bb637d5aa960ac391ca5a4cbf3e45807632e56beceeeb530e14dfa67fdfccc62" dependencies = [ "anyhow", "cpp_demangle", "cranelift-bitset", "cranelift-entity", "gimli", + "hashbrown 0.15.5", "indexmap", "log", "object", @@ -2207,23 +2216,24 @@ dependencies = [ "serde_derive", "smallvec", "target-lexicon", - "wasm-encoder 0.243.0", - "wasmparser 0.243.0", + "wasm-encoder 0.244.0", + "wasmparser 0.244.0", "wasmprinter", "wasmtime-internal-component-util", + "wasmtime-internal-core", ] [[package]] name = "wasmtime-internal-cache" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f52a985f5b5dae53147fc596f3a313c334e2c24fd1ba708634e1382f6ecd727" +checksum = "4ab6c428c610ae3e7acd25ca2681b4d23672c50d8769240d9dda99b751d4deec" dependencies = [ "base64", "directories-next", "log", "postcard", - "rustix 1.1.2", + "rustix 1.1.4", "serde", "serde_derive", "sha2", @@ -2235,9 +2245,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-macro" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7920dc7dcb608352f5fe93c52582e65075b7643efc5dac3fc717c1645a8d29a0" +checksum = "ca768b11d5e7de017e8c3d4d444da6b4ce3906f565bcbc253d76b4ecbb5d2869" dependencies = [ "anyhow", "proc-macro2", @@ -2245,20 +2255,30 @@ dependencies = [ "syn", "wasmtime-internal-component-util", "wasmtime-internal-wit-bindgen", - "wit-parser 0.243.0", + "wit-parser 0.244.0", ] [[package]] name = "wasmtime-internal-component-util" -version = "41.0.3" +version = "42.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763f504faf96c9b409051e96a1434655eea7f56a90bed9cb1e22e22c941253fd" + +[[package]] +name = "wasmtime-internal-core" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066f5aed35aa60580a2ac0df145c0f0d4b04319862fee1d6036693e1cca43a12" +checksum = "03a4a3f055a804a2f3d86e816a9df78a8fa57762212a8506164959224a40cd48" +dependencies = [ + "anyhow", + "libm", +] [[package]] name = "wasmtime-internal-cranelift" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb8002dc415b7773d7949ee360c05ee8f91627ec25a7a0b01ee03831bdfdda1" +checksum = "55154a91d22ad51f9551124ce7fb49ddddc6a82c4910813db4c790c97c9ccf32" dependencies = [ "cfg-if", "cranelift-codegen", @@ -2273,24 +2293,24 @@ dependencies = [ "pulley-interpreter", "smallvec", "target-lexicon", - "thiserror 2.0.17", - "wasmparser 0.243.0", + "thiserror 2.0.18", + "wasmparser 0.244.0", "wasmtime-environ", - "wasmtime-internal-math", + "wasmtime-internal-core", "wasmtime-internal-unwinder", "wasmtime-internal-versioned-export-macros", ] [[package]] name = "wasmtime-internal-fiber" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9c562c5a272bc9f615d8f0c085a4360bafa28eef9aa5947e63d204b1129b22" +checksum = "05decfad1021ad2efcca5c1be9855acb54b6ee7158ac4467119b30b7481508e3" dependencies = [ "cc", "cfg-if", "libc", - "rustix 1.1.2", + "rustix 1.1.4", "wasmtime-environ", "wasmtime-internal-versioned-export-macros", "windows-sys 0.61.2", @@ -2298,48 +2318,33 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-debug" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db673148f26e1211db3913c12c75594be9e3858a71fa297561e9162b1a49cfb0" +checksum = "924980c50427885fd4feed2049b88380178e567768aaabf29045b02eb262eaa7" dependencies = [ "cc", "object", - "rustix 1.1.2", + "rustix 1.1.4", "wasmtime-internal-versioned-export-macros", ] [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bada5ca1cc47df7d14100e2254e187c2486b426df813cea2dd2553a7469f7674" +checksum = "c57d24e8d1334a0e5a8b600286ffefa1fc4c3e8176b110dff6fbc1f43c4a599b" dependencies = [ - "anyhow", "cfg-if", "libc", + "wasmtime-internal-core", "windows-sys 0.61.2", ] -[[package]] -name = "wasmtime-internal-math" -version = "41.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf6f615d528eda9adc6eefb062135f831b5215c348f4c3ec3e143690c730605b" -dependencies = [ - "libm", -] - -[[package]] -name = "wasmtime-internal-slab" -version = "41.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da169d4f789b586e1b2612ba8399c653ed5763edf3e678884ba785bb151d018f" - [[package]] name = "wasmtime-internal-unwinder" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4888301f3393e4e8c75c938cce427293fade300fee3fc8fd466fdf3e54ae068e" +checksum = "3a1a144bd4393593a868ba9df09f34a6a360cb5db6e71815f20d3f649c6e6735" dependencies = [ "cfg-if", "cranelift-codegen", @@ -2350,9 +2355,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-versioned-export-macros" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63ba3124cc2cbcd362672f9f077303ccc4cd61daa908f73447b7fdaece75ff9f" +checksum = "9a6948b56bb00c62dbd205ea18a4f1ceccbe1e4b8479651fdb0bab2553790f20" dependencies = [ "proc-macro2", "quote", @@ -2361,16 +2366,16 @@ dependencies = [ [[package]] name = "wasmtime-internal-winch" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90a4182515dabba776656de4ebd62efad03399e261cf937ecccb838ce8823534" +checksum = "9130b3ab6fb01be80b27b9a2c84817af29ae8224094f2503d2afa9fea5bf9d00" dependencies = [ "cranelift-codegen", "gimli", "log", "object", "target-lexicon", - "wasmparser 0.243.0", + "wasmparser 0.244.0", "wasmtime-environ", "wasmtime-internal-cranelift", "winch-codegen", @@ -2378,24 +2383,23 @@ dependencies = [ [[package]] name = "wasmtime-internal-wit-bindgen" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87acbd416227cdd279565ba49e57cf7f08d112657c3b3f39b70250acdfd094fe" +checksum = "102d0d70dbfede00e4cc9c24e86df6d32c03bf6f5ad06b5d6c76b0a4a5004c4a" dependencies = [ "anyhow", "bitflags", "heck", "indexmap", - "wit-parser 0.243.0", + "wit-parser 0.244.0", ] [[package]] name = "wasmtime-wasi" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a1bdb4948463ed22559a640e687fed0df50b66353144aa6a9496c041ecd927" +checksum = "ea938f6f4f11e5ffe6d8b6f34c9a994821db9511c3e9c98e535896f27d06bb92" dependencies = [ - "anyhow", "async-trait", "bitflags", "bytes", @@ -2408,9 +2412,9 @@ dependencies = [ "futures", "io-extras", "io-lifetimes", - "rustix 1.1.2", + "rustix 1.1.4", "system-interface", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", "url", @@ -2422,14 +2426,14 @@ dependencies = [ [[package]] name = "wasmtime-wasi-io" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7873d8b990d3cf1105ef491abf2b3cf1e19ff6722d24d5ca662026ea082cdff" +checksum = "71cb16a88d0443b509d6eca4298617233265179090abf03e0a8042b9b251e9da" dependencies = [ - "anyhow", "async-trait", "bytes", "futures", + "tracing", "wasmtime", ] @@ -2444,59 +2448,59 @@ dependencies = [ [[package]] name = "wast" -version = "245.0.0" +version = "245.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ffc7471e16a6f3c7a3c3a230314915b5dcd158e5ef13ccda2f43358a9df00c" +checksum = "28cf1149285569120b8ce39db8b465e8a2b55c34cbb586bd977e43e2bc7300bf" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width", - "wasm-encoder 0.245.0", + "wasm-encoder 0.245.1", ] [[package]] name = "wat" -version = "1.245.0" +version = "1.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bcac6f915e2a84a4c0d9df9d41ad7518d99cda13f3bb83e3b8c22bf8726ab6" +checksum = "cd48d1679b6858988cb96b154dda0ec5bbb09275b71db46057be37332d5477be" dependencies = [ - "wast 245.0.0", + "wast 245.0.1", ] [[package]] name = "wiggle" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f05d2a9932ca235984248dc98471ae83d1985e095682d049af4c296f54f0fb4" +checksum = "2dca2bf96d20f0c70e6741cc6c8c1a9ee4c3c0310c7ad1971242628c083cc9a5" dependencies = [ - "anyhow", "bitflags", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "wasmtime", + "wasmtime-environ", "wiggle-macro", ] [[package]] name = "wiggle-generate" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f773d51c1696bd7d028aa35c884d9fc58f48d79a1176dfbad6c908de314235" +checksum = "d0d8c016d6d3ec6dc6b8c80c23cede4ee2386ccf347d01984f7991d7659f73ef" dependencies = [ - "anyhow", "heck", "proc-macro2", "quote", "syn", + "wasmtime-environ", "witx", ] [[package]] name = "wiggle-macro" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e976fe0cecd60041f66b15ad45ebc997952af13da9bf9d90261c7b025057edc" +checksum = "91a267096e48857096f035fffca29e22f0bbe840af4d74a6725eb695e1782110" dependencies = [ "proc-macro2", "quote", @@ -2537,22 +2541,21 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "41.0.3" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4f31dcfdfaf9d6df9e1124d7c8ee6fc29af5b99b89d11ae731c138e0f5bd77b" +checksum = "1977857998e4dd70d26e2bfc0618a9684a2fb65b1eca174dc13f3b3e9c2159ca" dependencies = [ - "anyhow", "cranelift-assembler-x64", "cranelift-codegen", "gimli", "regalloc2", "smallvec", "target-lexicon", - "thiserror 2.0.17", - "wasmparser 0.243.0", + "thiserror 2.0.18", + "wasmparser 0.244.0", "wasmtime-environ", + "wasmtime-internal-core", "wasmtime-internal-cranelift", - "wasmtime-internal-math", ] [[package]] @@ -2772,9 +2775,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" [[package]] name = "winx" @@ -2788,9 +2791,12 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro 0.51.0", +] [[package]] name = "wit-bindgen" @@ -2799,7 +2805,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e048f41ef90f0b5dd61f1059c35f5636252e56813bf616d0803aa3739867230" dependencies = [ "bitflags", - "wit-bindgen-rust-macro", + "wit-bindgen-rust-macro 0.52.0", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser 0.244.0", ] [[package]] @@ -2813,6 +2830,33 @@ dependencies = [ "wit-parser 0.244.0", ] +[[package]] +name = "wit-bindgen-core" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3deda4b7e9f522d994906f6e6e0fc67965ea8660306940a776b76732be8f3933" +dependencies = [ + "anyhow", + "heck", + "wit-parser 0.245.1", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata 0.244.0", + "wit-bindgen-core 0.51.0", + "wit-component 0.244.0", +] + [[package]] name = "wit-bindgen-rust" version = "0.52.0" @@ -2824,9 +2868,24 @@ dependencies = [ "indexmap", "prettyplease", "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", + "wasm-metadata 0.244.0", + "wit-bindgen-core 0.52.0", + "wit-component 0.244.0", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core 0.51.0", + "wit-bindgen-rust 0.51.0", ] [[package]] @@ -2840,8 +2899,8 @@ dependencies = [ "proc-macro2", "quote", "syn", - "wit-bindgen-core", - "wit-bindgen-rust", + "wit-bindgen-core 0.52.0", + "wit-bindgen-rust 0.52.0", ] [[package]] @@ -2858,16 +2917,35 @@ dependencies = [ "serde_derive", "serde_json", "wasm-encoder 0.244.0", - "wasm-metadata", + "wasm-metadata 0.244.0", "wasmparser 0.244.0", "wit-parser 0.244.0", ] +[[package]] +name = "wit-component" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4894f10d2d5cbc17c77e91f86a1e48e191a788da4425293b55c98b44ba3fcac9" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.245.1", + "wasm-metadata 0.245.1", + "wasmparser 0.245.1", + "wit-parser 0.245.1", +] + [[package]] name = "wit-parser" -version = "0.243.0" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df983a8608e513d8997f435bb74207bf0933d0e49ca97aa9d8a6157164b9b7fc" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", @@ -2878,16 +2956,17 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.243.0", + "wasmparser 0.244.0", ] [[package]] name = "wit-parser" -version = "0.244.0" +version = "0.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +checksum = "330698718e82983499419494dd1e3d7811a457a9bf9f69734e8c5f07a2547929" dependencies = [ "anyhow", + "hashbrown 0.16.1", "id-arena", "indexmap", "log", @@ -2896,7 +2975,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.244.0", + "wasmparser 0.245.1", ] [[package]] @@ -2942,18 +3021,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" dependencies = [ "proc-macro2", "quote", @@ -3014,6 +3093,12 @@ dependencies = [ "syn", ] +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index 72fdef2..c57f860 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,11 +23,11 @@ quote = "1.0.41" proc-macro2 = "1.0.103" syn = { version = "2.0.108", features = ["visit-mut"] } tempfile = "3.20.0" -wit-bindgen-core = "0.52.0" -wit-component = "0.244.0" +wit-bindgen-core = "0.53.1" +wit-component = "0.245.0" -wasmtime = { version = "41.0.0", features = ["wave"], optional = true } -wasmtime-wasi = { version = "41.0.0", optional = true } +wasmtime = { version = "42.0.0", features = ["wave"], optional = true } +wasmtime-wasi = { version = "42.0.0", optional = true } [features] run = ["wasmtime", "wasmtime-wasi"] diff --git a/Makefile b/Makefile index 793d55a..a58a380 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,15 @@ -.PHONY: all build-components build-cli test test-record test-fuzz run-fuzz run-record run-viceroy +.PHONY: all build-components build-cli test test-record test-host-replay test-fuzz run-fuzz run-record run-viceroy run-host-replay all: build-components build-cli build-cli: - cargo build --release + cargo build --all-features --release build-components: cargo build -p debug --target wasm32-wasip2 --release cargo build -p recorder --target wasm32-wasip2 --release cp target/wasm32-wasip2/release/debug.wasm assets/debug.wasm cp target/wasm32-wasip2/release/recorder.wasm assets/recorder.wasm -test: test-fuzz test-record +test: test-fuzz test-record test-host-replay test-fuzz: RUSTFLAGS="" $(MAKE) run-fuzz WASM=tests/calculator.wasm @@ -22,6 +22,11 @@ test-record: target/release/proxy-component instrument -m replay tests/rust.debug.wasm wasmtime --invoke 'start()' composed.wasm < trace.out +test-host-replay: + $(MAKE) run-host-replay WASM=tests/go.wasm + $(MAKE) run-host-replay WASM=tests/python.wasm + $(MAKE) run-host-replay WASM=tests/rust.wasm + run-fuzz: target/release/proxy-component instrument -m fuzz $(WASM) wasmtime --invoke 'start()' composed.wasm @@ -32,6 +37,12 @@ run-record: target/release/proxy-component instrument -m replay $(WASM) wasmtime --invoke 'start()' composed.wasm < trace.out +run-host-replay: + target/release/proxy-component instrument -m record $(WASM) + $(MAKE) run-viceroy URL=localhost:7676 + target/release/proxy-component instrument -m replay --use-host-recorder $(WASM) + target/release/proxy-component run composed.wasm --invoke 'start()' --trace trace.out + run-viceroy: viceroy composed.wasm > trace.out & echo $$! > viceroy.pid until nc -z localhost 7676; do \ diff --git a/assets/debug.wasm b/assets/debug.wasm index adde5e1ed0daa6ee599eadc76a2bce65ecade017..d22efa2ee77ae892be8f27d0ef85de41bc86156b 100644 GIT binary patch delta 711 zcmb`EJxml~5Qgvl_I3|UNDle&(1?Kq6AIvN_x5&2gCQu5F=8PC2SWDmgC(9vj>Esg zXd=egUACBl+Eyc1Tw1B zF{qUKKb3}3Ue`#^B-e05#g1eLB~Y?2-hrA@dv=uc9v74BvD>_Ld@qwNgp%ygFOn^z zpy;{Hz2CE1HXnEtNk`hg?MP|4t!`jJjCfw?7A()EAS@OFKbXngSuNi#J@&TZP16ag zm5TQ;^XUK`6ODjnS;@nt5`3yX0EZ zv3<8Sn}$7y6z?pe0B~y&a}eBB#v`QpRT-nu_Eg^G{0!qI`79gFUa7Z5zA!efrZn|4_J(jMF%it3Ms%mow-!sN>>E{x!zH0Co1OyuD%YAfAYx#Pz=$@??zp O|6zfZ1(P>6Q1}D;3BkAk delta 721 zcmb`C%WD%+7{%wzE2$8P+Qe3A!AgZL(#+hMxtUQ4(wdEkRj}43F=dj>#3_b^Wa?`n z6%=$CW^or?id)5IF(CL@b>q7KgG(vcm4dekhy|A}?t^oF=YIEW?(Hn2kPSn(OLcdV=dq zJd^Av9nk2D_y*>{m!9lL;|CgFcJ%#+Jh*mnJCP=iZxhopZKGgQ-6DgXU&~UOXqsmc z%k_PS5Ni4H3E+-6OI_PF>YiD*9M|%7uQ+jIy>y*EbbCRE6oOW#-3@!Je*w9)3OS{CY>7Jweg&HvoTaTAzSSwK3i#6yF zSiFW6fTc=!0EIm-VGc5TTf$42tWd@W?(LVkC$OM`TO9dR;fTb(Rq&aM@0yrqyLZ7m zMCar@OH{E4kzK9A87c9giX9bZ?0YbfId$0QV$jZe-EO;kS(_*G6bwaVc`DV!nJkq? zO#Ob4_Z|h|h+$959HG%oneS|>j7iXVp@|us&xVh4|9Vv!ju0of&EO-WNK=Q`<4sKF zsQf2&bdHj0Z-$-CFxLyap4(D~>8&!xGc*6-mg|JOo*)&E+N@rs0P HY(W1F+akkM diff --git a/assets/recorder.wasm b/assets/recorder.wasm index dbd56cd58723b64b0dc89f2e9ea6a545bee2cee2..3a7c0792546481b50c41020d8e5c1b94e8edf9a3 100644 GIT binary patch delta 43181 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 delta 42829 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 From 68b0f8f22bf893aa79560eae027acdc58edf0a3a Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Fri, 27 Feb 2026 19:11:45 -0800 Subject: [PATCH 6/6] fix --- Makefile | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index a58a380..8fa07f1 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all build-components build-cli test test-record test-host-replay test-fuzz run-fuzz run-record run-viceroy run-host-replay +.PHONY: all build-components build-cli test test-record test-fuzz run-fuzz run-record run-viceroy all: build-components build-cli build-cli: @@ -9,7 +9,7 @@ build-components: cp target/wasm32-wasip2/release/debug.wasm assets/debug.wasm cp target/wasm32-wasip2/release/recorder.wasm assets/recorder.wasm -test: test-fuzz test-record test-host-replay +test: test-fuzz test-record test-fuzz: RUSTFLAGS="" $(MAKE) run-fuzz WASM=tests/calculator.wasm @@ -22,11 +22,6 @@ test-record: target/release/proxy-component instrument -m replay tests/rust.debug.wasm wasmtime --invoke 'start()' composed.wasm < trace.out -test-host-replay: - $(MAKE) run-host-replay WASM=tests/go.wasm - $(MAKE) run-host-replay WASM=tests/python.wasm - $(MAKE) run-host-replay WASM=tests/rust.wasm - run-fuzz: target/release/proxy-component instrument -m fuzz $(WASM) wasmtime --invoke 'start()' composed.wasm @@ -36,10 +31,7 @@ run-record: $(MAKE) run-viceroy URL=localhost:7676 target/release/proxy-component instrument -m replay $(WASM) wasmtime --invoke 'start()' composed.wasm < trace.out - -run-host-replay: - target/release/proxy-component instrument -m record $(WASM) - $(MAKE) run-viceroy URL=localhost:7676 + # test host replay target/release/proxy-component instrument -m replay --use-host-recorder $(WASM) target/release/proxy-component run composed.wasm --invoke 'start()' --trace trace.out