diff --git a/Cargo.lock b/Cargo.lock index c144d7d9ec..cdf16629bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3621,9 +3621,9 @@ dependencies = [ [[package]] name = "golem-examples" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883c58ea3a337455fa86e0432bf80795ed52502e29fb93b7d5ab29dc57c23cb0" +checksum = "31f5befbcc7d078f904ac2b62a7e97eafaddfcabe053c0de975919053ed4a87c" dependencies = [ "Inflector", "cargo_metadata", @@ -9546,6 +9546,7 @@ checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", "serde 1.0.207", + "sha1_smol", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9f3dd9b14b..4e0111747c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -191,7 +191,7 @@ tracing-subscriber = { version = "0.3.18", features = [ ] } tracing-test = "0.2.5" url = "2.5.0" -uuid = { version = "1.7.0", features = ["serde", "v4"] } +uuid = { version = "1.7.0", features = ["serde", "v4", "v5"] } warp = "0.3.6" wasm-wave = "=0.6.0" wasmtime = { version = "=21.0.1", features = ["component-model"] } diff --git a/golem-api-grpc/proto/golem/rib/expr.proto b/golem-api-grpc/proto/golem/rib/expr.proto index fb5690c0d7..f9bc9eadde 100644 --- a/golem-api-grpc/proto/golem/rib/expr.proto +++ b/golem-api-grpc/proto/golem/rib/expr.proto @@ -169,10 +169,20 @@ message ResultExpr { } message CallExpr { - InvocationName name = 1; + optional InvocationName name = 1; repeated Expr params = 2; + optional CallType call_type = 3; } +message CallType { + oneof name { + golem.rib.DynamicParsedFunctionName parsed = 1; + string variant_constructor = 2; + string enum_constructor = 3; + } +} + +/** Legacy call-type that holds fully formed function names and not dynamic functions. This is kept for backward compatibility */ message InvocationName { oneof name { golem.rib.ParsedFunctionName parsed = 1; @@ -217,3 +227,44 @@ message TupleConstructorArmPattern { message LiteralArmPattern { Expr expr = 1; } + +message DynamicParsedFunctionName { + golem.rib.ParsedFunctionSite site = 1; + DynamicParsedFunctionReference function = 2; +} + +message DynamicParsedFunctionReference { + oneof function_reference { + golem.rib.FunctionFunctionReference function = 1; + golem.rib.RawResourceConstructorFunctionReference raw_resource_constructor = 2; + golem.rib.RawResourceDropFunctionReference raw_resource_drop = 3; + golem.rib.RawResourceMethodFunctionReference raw_resource_method = 4; + golem.rib.RawResourceStaticMethodFunctionReference raw_resource_static_method = 5; + DynamicIndexedResourceConstructorFunctionReference indexed_resource_constructor = 6; + DynamicIndexedResourceMethodFunctionReference indexed_resource_method = 7; + DynamicIndexedResourceStaticMethodFunctionReference indexed_resource_static_method = 8; + DynamicIndexedResourceDropFunctionReference indexed_resource_drop = 9; + } +} + +message DynamicIndexedResourceConstructorFunctionReference { + string resource = 1; + repeated golem.rib.Expr resource_params = 2; +} + +message DynamicIndexedResourceMethodFunctionReference { + string resource = 1; + repeated golem.rib.Expr resource_params = 2; + string method = 3; +} + +message DynamicIndexedResourceStaticMethodFunctionReference { + string resource = 1; + repeated golem.rib.Expr resource_params = 2; + string method = 3; +} + +message DynamicIndexedResourceDropFunctionReference { + string resource = 1; + repeated golem.rib.Expr resource_params = 2; +} \ No newline at end of file diff --git a/golem-api-grpc/proto/golem/rib/function_name.proto b/golem-api-grpc/proto/golem/rib/function_name.proto index aa9dc5370e..49cf695d7d 100644 --- a/golem-api-grpc/proto/golem/rib/function_name.proto +++ b/golem-api-grpc/proto/golem/rib/function_name.proto @@ -94,4 +94,4 @@ message IndexedResourceStaticMethodFunctionReference { message IndexedResourceDropFunctionReference { string resource = 1; repeated string resource_params = 2; -} \ No newline at end of file +} diff --git a/golem-api-grpc/proto/golem/rib/ir.proto b/golem-api-grpc/proto/golem/rib/ir.proto index 4225db4728..f5f0d7f5a7 100644 --- a/golem-api-grpc/proto/golem/rib/ir.proto +++ b/golem-api-grpc/proto/golem/rib/ir.proto @@ -6,6 +6,8 @@ import "wasm/ast/type.proto"; import "wasm/rpc/type_annotated_value.proto"; +import "golem/rib/function_name.proto"; + message RibIR { oneof instruction { wasm.rpc.TypeAnnotatedValue push_lit = 1; @@ -39,6 +41,7 @@ message RibIR { ConcatInstruction concat = 29; EnumConstructionInstruction enum_construction = 30; And and = 31; + CreateFunctionNameInstruction create_function_name = 32; } } @@ -83,7 +86,6 @@ message JumpInstruction { } message CallInstruction { - string function_name = 1; uint64 argument_count = 2; wasm.ast.Type return_type = 3; } @@ -98,6 +100,12 @@ message EnumConstructionInstruction { wasm.ast.Type return_type = 2; } +message CreateFunctionNameInstruction { + golem.rib.ParsedFunctionSite site = 1; + FunctionReferenceType function_reference_details = 2; +} + + message EqualTo {} message GreaterThan {} message LessThan {} @@ -106,3 +114,61 @@ message LessThanOrEqualTo {} message GetTag {} message Negate {} message And {} + +message FunctionReferenceType { + oneof type { + Function function = 1; + RawResourceConstructor raw_resource_constructor = 2; + RawResourceDrop raw_resource_drop = 3; + RawResourceMethod raw_resource_method = 4; + RawResourceStaticMethod raw_resource_static_method = 5; + IndexedResourceConstructor indexed_resource_constructor = 6; + IndexedResourceMethod indexed_resource_method = 7; + IndexedResourceStaticMethod indexed_resource_static_method = 8; + IndexedResourceDrop indexed_resource_drop = 9; + } +} + +message Function { + string name = 1; +} + +message RawResourceConstructor { + string resource_name = 1; +} + +message RawResourceDrop { + string resource_name = 1; +} + +message RawResourceMethod { + string resource_name = 1; + string method_name = 2; +} + +message RawResourceStaticMethod { + string resource_name = 1; + string method_name = 2; +} + +message IndexedResourceConstructor { + string resource_name = 1; + uint32 arg_size = 2; +} + +message IndexedResourceMethod { + string resource_name = 1; + uint32 arg_size = 2; + string method_name = 3; +} + +message IndexedResourceStaticMethod { + string resource_name = 1; + uint32 arg_size = 2; + string method_name = 3; +} + +message IndexedResourceDrop { + string resource_name = 1; + uint32 arg_size = 2; +} diff --git a/golem-cli/Cargo.toml b/golem-cli/Cargo.toml index a31e953d44..382321ce9e 100644 --- a/golem-cli/Cargo.toml +++ b/golem-cli/Cargo.toml @@ -36,7 +36,7 @@ colored = "2.1.0" derive_more = { workspace = true } dirs = "5.0.1" futures-util = { workspace = true } -golem-examples = "1.0.5" +golem-examples = "1.0.6" golem-wasm-ast = { workspace = true } golem-wasm-rpc = { workspace = true } golem-wasm-rpc-stubgen = { version = "1.0.3", optional = true } diff --git a/golem-cli/tests/text.rs b/golem-cli/tests/text.rs index bb6a355a9c..e6712e85c1 100644 --- a/golem-cli/tests/text.rs +++ b/golem-cli/tests/text.rs @@ -271,7 +271,7 @@ fn text_component_list( +----------------------------------------------------+-------------------------------+---------+-------+---------------+ | URN | Name | Version | Size | Exports count | +----------------------------------------------------+-------------------------------+---------+-------+---------------+ - | {} | {} | 0 | 71828 | 2 | + | {} | {} | 0 | 71228 | 2 | +----------------------------------------------------+-------------------------------+---------+-------+---------------+ ", component.component_urn, diff --git a/golem-common/src/model/mod.rs b/golem-common/src/model/mod.rs index 5d79563888..2ce75efe78 100644 --- a/golem-common/src/model/mod.rs +++ b/golem-common/src/model/mod.rs @@ -42,7 +42,7 @@ use poem_openapi::{Enum, Object, Union}; use rand::prelude::IteratorRandom; use serde::{Deserialize, Serialize, Serializer}; use serde_json::Value; -use uuid::Uuid; +use uuid::{uuid, Uuid}; pub mod component_metadata; pub mod exports; @@ -788,6 +788,8 @@ pub struct IdempotencyKey { } impl IdempotencyKey { + const ROOT_NS: Uuid = uuid!("9C19B15A-C83D-46F7-9BC3-EAD7923733F4"); + pub fn new(value: String) -> Self { Self { value } } @@ -801,6 +803,25 @@ impl IdempotencyKey { pub fn fresh() -> Self { Self::from_uuid(Uuid::new_v4()) } + + /// Generates a deterministic new idempotency key using a base idempotency key and an oplog index. + /// + /// The base idempotency key determines the "namespace" of the generated key UUIDv5. If + /// the base idempotency key is already an UUID, it is directly used as the namespace of the v5 algorithm, + /// while the name part is derived from the given oplog index. + /// + /// If the base idempotency key is not an UUID (as it can be an arbitrary user-provided string), then first + /// we generate a UUIDv5 in the ROOT_NS namespace and use that as unique namespace for generating + /// the new idempotency key. + pub fn derived(base: &IdempotencyKey, oplog_index: OplogIndex) -> Self { + let namespace = if let Ok(base_uuid) = Uuid::parse_str(&base.value) { + base_uuid + } else { + Uuid::new_v5(&Self::ROOT_NS, base.value.as_bytes()) + }; + let name = format!("oplog-index-{}", oplog_index); + Self::from_uuid(Uuid::new_v5(&namespace, name.as_bytes())) + } } impl From for IdempotencyKey { @@ -2342,9 +2363,11 @@ mod tests { use std::time::SystemTime; use std::vec; + use crate::model::oplog::OplogIndex; use crate::model::{ - AccountId, ComponentId, FilterComparator, ShardId, StringFilterComparator, TargetWorkerId, - Timestamp, WorkerFilter, WorkerId, WorkerMetadata, WorkerStatus, WorkerStatusRecord, + AccountId, ComponentId, FilterComparator, IdempotencyKey, ShardId, StringFilterComparator, + TargetWorkerId, Timestamp, WorkerFilter, WorkerId, WorkerMetadata, WorkerStatus, + WorkerStatusRecord, }; use bincode::{Decode, Encode}; use rand::{thread_rng, Rng}; @@ -2620,4 +2643,49 @@ mod tests { } } } + + #[test] + fn derived_idempotency_key() { + let base1 = IdempotencyKey::fresh(); + let base2 = IdempotencyKey::fresh(); + let base3 = IdempotencyKey { + value: "base3".to_string(), + }; + + assert_ne!(base1, base2); + + let idx1 = OplogIndex::from_u64(2); + let idx2 = OplogIndex::from_u64(11); + + let derived11a = IdempotencyKey::derived(&base1, idx1); + let derived12a = IdempotencyKey::derived(&base1, idx2); + let derived21a = IdempotencyKey::derived(&base2, idx1); + let derived22a = IdempotencyKey::derived(&base2, idx2); + + let derived11b = IdempotencyKey::derived(&base1, idx1); + let derived12b = IdempotencyKey::derived(&base1, idx2); + let derived21b = IdempotencyKey::derived(&base2, idx1); + let derived22b = IdempotencyKey::derived(&base2, idx2); + + let derived31 = IdempotencyKey::derived(&base3, idx1); + let derived32 = IdempotencyKey::derived(&base3, idx2); + + assert_eq!(derived11a, derived11b); + assert_eq!(derived12a, derived12b); + assert_eq!(derived21a, derived21b); + assert_eq!(derived22a, derived22b); + + assert_ne!(derived11a, derived12a); + assert_ne!(derived11a, derived21a); + assert_ne!(derived11a, derived22a); + assert_ne!(derived12a, derived21a); + assert_ne!(derived12a, derived22a); + assert_ne!(derived21a, derived22a); + + assert_ne!(derived11a, derived31); + assert_ne!(derived21a, derived31); + assert_ne!(derived12a, derived32); + assert_ne!(derived22a, derived32); + assert_ne!(derived31, derived32); + } } diff --git a/golem-rib/src/call_type.rs b/golem-rib/src/call_type.rs index f0ef76e7d4..3f752f0f95 100644 --- a/golem-rib/src/call_type.rs +++ b/golem-rib/src/call_type.rs @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::ParsedFunctionName; +use crate::{DynamicParsedFunctionName, ParsedFunctionName}; use bincode::{Decode, Encode}; use std::convert::TryFrom; use std::fmt::Display; #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub enum CallType { - Function(ParsedFunctionName), + Function(DynamicParsedFunctionName), VariantConstructor(String), EnumConstructor(String), } @@ -34,49 +34,67 @@ impl Display for CallType { } } -impl TryFrom for CallType { +impl TryFrom for CallType { type Error = String; - fn try_from( - value: golem_api_grpc::proto::golem::rib::InvocationName, - ) -> Result { + fn try_from(value: golem_api_grpc::proto::golem::rib::CallType) -> Result { let invocation = value.name.ok_or("Missing name of invocation")?; match invocation { - golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed(name) => { - Ok(CallType::Function(ParsedFunctionName::try_from(name)?)) - } - golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor(name) => { + golem_api_grpc::proto::golem::rib::call_type::Name::Parsed(name) => Ok( + CallType::Function(DynamicParsedFunctionName::try_from(name)?), + ), + golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(name) => { Ok(CallType::VariantConstructor(name)) } - golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor(name) => { + golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name) => { Ok(CallType::EnumConstructor(name)) } } } } -impl From for golem_api_grpc::proto::golem::rib::InvocationName { +impl From for golem_api_grpc::proto::golem::rib::CallType { fn from(value: CallType) -> Self { match value { - CallType::Function(parsed_name) => { - golem_api_grpc::proto::golem::rib::InvocationName { - name: Some(golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed( - parsed_name.into(), - )), - } + CallType::Function(parsed_name) => golem_api_grpc::proto::golem::rib::CallType { + name: Some(golem_api_grpc::proto::golem::rib::call_type::Name::Parsed( + parsed_name.into(), + )), + }, + CallType::VariantConstructor(name) => golem_api_grpc::proto::golem::rib::CallType { + name: Some( + golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(name), + ), + }, + CallType::EnumConstructor(name) => golem_api_grpc::proto::golem::rib::CallType { + name: Some( + golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name), + ), + }, + } + } +} + +// InvocationName is a legacy structure to keep the backward compatibility. +// InvocationName is corresponding to the new CallType and the difference here is, +// InvocationName::Function will always hold a static function name and not a dynamic one +// with Expr representing resource construction parameters +impl TryFrom for CallType { + type Error = String; + fn try_from( + value: golem_api_grpc::proto::golem::rib::InvocationName, + ) -> Result { + let invocation = value.name.ok_or("Missing name of invocation")?; + match invocation { + golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed(name) => { + Ok(CallType::Function(DynamicParsedFunctionName::parse( + ParsedFunctionName::try_from(name)?.to_string(), + )?)) } - CallType::VariantConstructor(name) => { - golem_api_grpc::proto::golem::rib::InvocationName { - name: Some(golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor( - name, - )), - } + golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor(name) => { + Ok(CallType::VariantConstructor(name)) } - CallType::EnumConstructor(name) => { - golem_api_grpc::proto::golem::rib::InvocationName { - name: Some(golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor( - name, - )), - } + golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor(name) => { + Ok(CallType::EnumConstructor(name)) } } } diff --git a/golem-rib/src/compiler/byte_code.rs b/golem-rib/src/compiler/byte_code.rs index 8b970b9872..86af7a7c13 100644 --- a/golem-rib/src/compiler/byte_code.rs +++ b/golem-rib/src/compiler/byte_code.rs @@ -17,9 +17,8 @@ use crate::compiler::ir::RibIR; use crate::{Expr, InstructionId}; use bincode::{Decode, Encode}; use golem_api_grpc::proto::golem::rib::RibByteCode as ProtoRibByteCode; -use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Encode, Decode)] pub struct RibByteCode { pub instructions: Vec, } @@ -84,7 +83,10 @@ impl From for ProtoRibByteCode { mod internal { use crate::compiler::desugar::desugar_pattern_match; - use crate::{AnalysedTypeWithUnit, Expr, InferredType, InstructionId, RibIR}; + use crate::{ + AnalysedTypeWithUnit, DynamicParsedFunctionReference, Expr, FunctionReferenceType, + InferredType, InstructionId, RibIR, + }; use golem_wasm_ast::analysis::AnalysedType; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; @@ -251,11 +253,121 @@ mod internal { )?) }; - instructions.push(RibIR::InvokeFunction( - parsed_function_name.clone(), - arguments.len(), - function_result_type, - )); + instructions + .push(RibIR::InvokeFunction(arguments.len(), function_result_type)); + + let site = parsed_function_name.site.clone(); + + match &parsed_function_name.function { + DynamicParsedFunctionReference::Function { function } => instructions + .push(RibIR::CreateFunctionName( + site, + FunctionReferenceType::Function { + function: function.clone(), + }, + )), + + DynamicParsedFunctionReference::RawResourceConstructor { resource } => { + instructions.push(RibIR::CreateFunctionName( + site, + FunctionReferenceType::RawResourceConstructor { + resource: resource.clone(), + }, + )) + } + DynamicParsedFunctionReference::RawResourceDrop { resource } => { + instructions.push(RibIR::CreateFunctionName( + site, + FunctionReferenceType::RawResourceDrop { + resource: resource.clone(), + }, + )) + } + DynamicParsedFunctionReference::RawResourceMethod { + resource, + method, + } => instructions.push(RibIR::CreateFunctionName( + site, + FunctionReferenceType::RawResourceMethod { + resource: resource.clone(), + method: method.clone(), + }, + )), + DynamicParsedFunctionReference::RawResourceStaticMethod { + resource, + method, + } => instructions.push(RibIR::CreateFunctionName( + site, + FunctionReferenceType::RawResourceStaticMethod { + resource: resource.clone(), + method: method.clone(), + }, + )), + DynamicParsedFunctionReference::IndexedResourceConstructor { + resource, + resource_params, + } => { + for param in resource_params { + stack.push(ExprState::from_expr(param)); + } + instructions.push(RibIR::CreateFunctionName( + site, + FunctionReferenceType::IndexedResourceConstructor { + resource: resource.clone(), + arg_size: resource_params.len(), + }, + )) + } + DynamicParsedFunctionReference::IndexedResourceMethod { + resource, + resource_params, + method, + } => { + for param in resource_params { + stack.push(ExprState::from_expr(param)); + } + instructions.push(RibIR::CreateFunctionName( + site, + FunctionReferenceType::IndexedResourceMethod { + resource: resource.clone(), + arg_size: resource_params.len(), + method: method.clone(), + }, + )) + } + DynamicParsedFunctionReference::IndexedResourceStaticMethod { + resource, + resource_params, + method, + } => { + for param in resource_params { + stack.push(ExprState::from_expr(param)); + } + instructions.push(RibIR::CreateFunctionName( + site, + FunctionReferenceType::IndexedResourceStaticMethod { + resource: resource.clone(), + arg_size: resource_params.len(), + method: method.clone(), + }, + )) + } + DynamicParsedFunctionReference::IndexedResourceDrop { + resource, + resource_params, + } => { + for param in resource_params { + stack.push(ExprState::from_expr(param)); + } + instructions.push(RibIR::CreateFunctionName( + site, + FunctionReferenceType::IndexedResourceDrop { + resource: resource.clone(), + arg_size: resource_params.len(), + }, + )) + } + } } CallType::VariantConstructor(variant_name) => { @@ -380,6 +492,7 @@ mod internal { stack.push(ExprState::from_ir(RibIR::Label(else_ending_id.clone()))); } } + #[cfg(test)] mod compiler_tests { use super::*; diff --git a/golem-rib/src/compiler/ir.rs b/golem-rib/src/compiler/ir.rs index efb7c0d5c3..2d7722e30b 100644 --- a/golem-rib/src/compiler/ir.rs +++ b/golem-rib/src/compiler/ir.rs @@ -12,20 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{AnalysedTypeWithUnit, ParsedFunctionName, VariableId}; +use crate::{AnalysedTypeWithUnit, ParsedFunctionSite, VariableId}; use bincode::{Decode, Encode}; use golem_api_grpc::proto::golem::rib::rib_ir::Instruction; use golem_api_grpc::proto::golem::rib::{ - And, CallInstruction, ConcatInstruction, EqualTo, GetTag, GreaterThan, GreaterThanOrEqualTo, - JumpInstruction, LessThan, LessThanOrEqualTo, Negate, PushListInstruction, PushNoneInstruction, - PushTupleInstruction, RibIr as ProtoRibIR, + And, CallInstruction, ConcatInstruction, CreateFunctionNameInstruction, EqualTo, GetTag, + GreaterThan, GreaterThanOrEqualTo, JumpInstruction, LessThan, LessThanOrEqualTo, Negate, + PushListInstruction, PushNoneInstruction, PushTupleInstruction, RibIr as ProtoRibIR, }; use golem_wasm_ast::analysis::{AnalysedType, TypeStr}; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use serde::{Deserialize, Serialize}; // To create any type, example, CreateOption, you have to feed a fully formed AnalysedType -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Encode, Decode)] pub enum RibIR { PushLit(TypeAnnotatedValue), AssignVar(VariableId), @@ -51,7 +51,8 @@ pub enum RibIR { Jump(InstructionId), Label(InstructionId), Deconstruct, - InvokeFunction(ParsedFunctionName, usize, AnalysedTypeWithUnit), + CreateFunctionName(ParsedFunctionSite, FunctionReferenceType), + InvokeFunction(usize, AnalysedTypeWithUnit), PushVariant(String, AnalysedType), // There is no arg size since the type of each variant case is only 1 from beginning PushEnum(String, AnalysedType), Throw(String), @@ -60,6 +61,160 @@ pub enum RibIR { Negate, } +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +pub enum FunctionReferenceType { + Function { + function: String, + }, + RawResourceConstructor { + resource: String, + }, + RawResourceDrop { + resource: String, + }, + RawResourceMethod { + resource: String, + method: String, + }, + RawResourceStaticMethod { + resource: String, + method: String, + }, + IndexedResourceConstructor { + resource: String, + arg_size: usize, + }, + IndexedResourceMethod { + resource: String, + arg_size: usize, + method: String, + }, + IndexedResourceStaticMethod { + resource: String, + arg_size: usize, + method: String, + }, + IndexedResourceDrop { + resource: String, + arg_size: usize, + }, +} + +impl TryFrom for FunctionReferenceType { + type Error = String; + fn try_from( + value: golem_api_grpc::proto::golem::rib::FunctionReferenceType, + ) -> Result { + let value = value.r#type.ok_or("Missing type".to_string())?; + let function_reference_type = match value { + golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(name) => FunctionReferenceType::Function { + function: name.name + }, + golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(name) => + FunctionReferenceType::RawResourceConstructor { + resource: name.resource_name + }, + golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(name) => FunctionReferenceType::RawResourceDrop { + resource: name.resource_name + }, + golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(raw_resource_method) =>{ + let resource = raw_resource_method.resource_name; + let method = raw_resource_method.method_name; + FunctionReferenceType::RawResourceMethod { resource, method } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(raw_resource_static_method) => { + let resource = raw_resource_static_method.resource_name; + let method = raw_resource_static_method.method_name; + FunctionReferenceType::RawResourceStaticMethod{ resource, method } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceConstructor(indexed_resource_constructor) => { + let resource = indexed_resource_constructor.resource_name; + let arg_size = indexed_resource_constructor.arg_size; + FunctionReferenceType::IndexedResourceConstructor { resource, arg_size: arg_size as usize } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceMethod(indexed_resource_method) => { + let resource = indexed_resource_method.resource_name; + let arg_size = indexed_resource_method.arg_size; + let method = indexed_resource_method.method_name; + FunctionReferenceType::IndexedResourceMethod { resource, arg_size: arg_size as usize, method } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceStaticMethod(indexed_resource_static_method) => { + let resource = indexed_resource_static_method.resource_name; + let arg_size = indexed_resource_static_method.arg_size; + let method = indexed_resource_static_method.method_name; + FunctionReferenceType::IndexedResourceStaticMethod { resource, arg_size: arg_size as usize, method } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceDrop(indexed_resource_drop) => { + let resource = indexed_resource_drop.resource_name; + let arg_size = indexed_resource_drop.arg_size; + FunctionReferenceType::IndexedResourceDrop { resource, arg_size: arg_size as usize } + } + }; + Ok(function_reference_type) + } +} + +impl From for golem_api_grpc::proto::golem::rib::FunctionReferenceType { + fn from(value: FunctionReferenceType) -> Self { + match value { + FunctionReferenceType::Function { function } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(golem_api_grpc::proto::golem::rib::Function { + name: function + })) + }, + FunctionReferenceType::RawResourceConstructor{ resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructor { + resource_name: resource + })) + }, + FunctionReferenceType::RawResourceDrop { resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDrop { + resource_name: resource + })) + }, + FunctionReferenceType::RawResourceMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethod { + resource_name: resource, + method_name: method + })) + }, + FunctionReferenceType::RawResourceStaticMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethod { + resource_name: resource, + method_name: method + })) + }, + FunctionReferenceType::IndexedResourceConstructor { resource, arg_size } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::IndexedResourceConstructor { + resource_name: resource, + arg_size: arg_size as u32 + })) + }, + FunctionReferenceType::IndexedResourceMethod { resource, arg_size, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::IndexedResourceMethod { + resource_name: resource, + arg_size: arg_size as u32, + method_name: method + })) + }, + FunctionReferenceType::IndexedResourceStaticMethod { resource, arg_size, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethod { + resource_name: resource, + arg_size: arg_size as u32, + method_name: method + })) + }, + FunctionReferenceType::IndexedResourceDrop { resource, arg_size } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::IndexedResourceDrop { + resource_name: resource, + arg_size: arg_size as u32 + })) + } + + } + } +} + // Every instruction can have a unique ID, and the compiler // can assign this and label the start and end of byte code blocks. // This is more efficient than assigning index to every instruction and incrementing it @@ -186,8 +341,6 @@ impl TryFrom for RibIR { }; Ok(RibIR::InvokeFunction( - ParsedFunctionName::parse(call_instruction.function_name) - .map_err(|_| "Failed to convert ParsedFunctionName".to_string())?, call_instruction.argument_count as usize, return_type, )) @@ -244,6 +397,20 @@ impl TryFrom for RibIR { Instruction::Concat(concat_instruction) => { Ok(RibIR::Concat(concat_instruction.arg_size as usize)) } + Instruction::CreateFunctionName(instruction) => { + let parsed_site = instruction.site.ok_or("Missing site".to_string())?; + let parsed_function_site = ParsedFunctionSite::try_from(parsed_site)?; + + let reference_type = instruction + .function_reference_details + .ok_or("Missing reference_type".to_string())?; + let function_reference_type = reference_type.try_into()?; + + Ok(RibIR::CreateFunctionName( + parsed_function_site, + function_reference_type, + )) + } } } } @@ -293,7 +460,7 @@ impl From for ProtoRibIR { instruction_id: value.index as u64, }), RibIR::Deconstruct => Instruction::Deconstruct((&AnalysedType::Str(TypeStr)).into()), //TODO; remove type in deconstruct from protobuf - RibIR::InvokeFunction(name, arg_count, return_type) => { + RibIR::InvokeFunction(arg_count, return_type) => { let typ = match return_type { AnalysedTypeWithUnit::Unit => None, AnalysedTypeWithUnit::Type(analysed_type) => { @@ -303,7 +470,6 @@ impl From for ProtoRibIR { }; Instruction::Call(CallInstruction { - function_name: name.to_string(), argument_count: arg_count as u64, return_type: typ, }) @@ -347,6 +513,12 @@ impl From for ProtoRibIR { arg_size: concat as u64, }), RibIR::Negate => Instruction::Negate(Negate {}), + RibIR::CreateFunctionName(site, reference_type) => { + Instruction::CreateFunctionName(CreateFunctionNameInstruction { + site: Some(site.into()), + function_reference_details: Some(reference_type.into()), + }) + } }; ProtoRibIR { diff --git a/golem-rib/src/expr.rs b/golem-rib/src/expr.rs index 3b7d6cf08d..a6686229ea 100644 --- a/golem-rib/src/expr.rs +++ b/golem-rib/src/expr.rs @@ -13,11 +13,12 @@ // limitations under the License. use crate::call_type::CallType; -use crate::function_name::ParsedFunctionName; use crate::parser::rib_expr::rib_program; use crate::parser::type_name::TypeName; use crate::type_registry::FunctionTypeRegistry; -use crate::{text, type_inference, InferredType, VariableId}; +use crate::{ + text, type_inference, DynamicParsedFunctionName, InferredType, ParsedFunctionName, VariableId, +}; use bincode::{Decode, Encode}; use combine::stream::position; use combine::EasyParser; @@ -30,7 +31,7 @@ use std::fmt::Display; use std::ops::Deref; use std::str::FromStr; -#[derive(Debug, Clone, PartialEq, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] pub enum Expr { Let(VariableId, Option, Box, InferredType), SelectField(Box, String, InferredType), @@ -256,9 +257,9 @@ impl Expr { cond } - pub fn call(parsed_fn_name: ParsedFunctionName, args: Vec) -> Self { + pub fn call(dynamic_parsed_fn_name: DynamicParsedFunctionName, args: Vec) -> Self { Expr::Call( - CallType::Function(parsed_fn_name), + CallType::Function(dynamic_parsed_fn_name), args, InferredType::Unknown, ) @@ -697,6 +698,8 @@ pub struct Number { pub value: f64, // Change to bigdecimal } +impl Eq for Number {} + impl Number { pub fn to_val(&self, analysed_type: &AnalysedType) -> Option { match analysed_type { @@ -721,7 +724,7 @@ impl Display for Number { } } -#[derive(Debug, Clone, PartialEq, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] pub struct MatchArm { pub arm_pattern: ArmPattern, pub arm_resolution_expr: Box, @@ -735,7 +738,7 @@ impl MatchArm { } } } -#[derive(Debug, Clone, PartialEq, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] pub enum ArmPattern { WildCard, As(String, Box), @@ -1050,18 +1053,43 @@ impl TryFrom for Expr { .into_iter() .map(|expr| expr.try_into()) .collect::, _>>()?; - let invocation_name = expr.name.ok_or("Missing invocation name")?; - let name = invocation_name.name.ok_or("Missing function call name")?; - match name { - golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed(name) => { - Expr::call(name.try_into()?, params) + // This is not required and kept for backward compatibility + let legacy_invocation_name = expr.name; + let call_type = expr.call_type; + + match (legacy_invocation_name, call_type) { + (Some(legacy), None) => { + let name = legacy.name.ok_or("Missing function call name")?; + match name { + golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed(name) => { + // Reading the previous parsed-function-name in persistent store as a dynamic-parsed-function-name + Expr::call(DynamicParsedFunctionName::parse( + ParsedFunctionName::try_from(name)?.to_string() + )?, params) + } + golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor( + name, + ) => Expr::call(DynamicParsedFunctionName::parse(name)?, params), + golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor( + name, + ) => Expr::call(DynamicParsedFunctionName::parse(name)?, params), + } } - golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor( - name, - ) => Expr::call(ParsedFunctionName::parse(name)?, params), - golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor( - name, - ) => Expr::call(ParsedFunctionName::parse(name)?, params), + (_, Some(call_type)) => { + let name = call_type.name.ok_or("Missing function call name")?; + match name { + golem_api_grpc::proto::golem::rib::call_type::Name::Parsed(name) => { + Expr::call(name.try_into()?, params) + } + golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor( + name, + ) => Expr::call(DynamicParsedFunctionName::parse(name)?, params), + golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor( + name, + ) => Expr::call(DynamicParsedFunctionName::parse(name)?, params), + } + } + (_, _) => Err("Missing both call type (and legacy invocation type)")?, } } }; @@ -1248,8 +1276,9 @@ impl From for golem_api_grpc::proto::golem::rib::Expr { Expr::Call(function_name, args, _) => { Some(golem_api_grpc::proto::golem::rib::expr::Expr::Call( golem_api_grpc::proto::golem::rib::CallExpr { - name: Some(function_name.into()), + name: None, params: args.into_iter().map(|expr| expr.into()).collect(), + call_type: Some(function_name.into()), }, )) } diff --git a/golem-rib/src/function_name.rs b/golem-rib/src/function_name.rs index 0b3f8af3dd..ab76052110 100644 --- a/golem-rib/src/function_name.rs +++ b/golem-rib/src/function_name.rs @@ -12,9 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::{text, Expr}; use bincode::{BorrowDecode, Decode, Encode}; use combine::stream::easy; use combine::EasyParser; +use golem_api_grpc::proto::golem::rib::dynamic_parsed_function_reference::FunctionReference as ProtoDynamicFunctionReference; use golem_wasm_ast::analysis::AnalysedType; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use golem_wasm_rpc::type_annotated_value_from_str; @@ -266,6 +268,143 @@ pub enum ParsedFunctionReference { }, } +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +pub enum DynamicParsedFunctionReference { + Function { + function: String, + }, + RawResourceConstructor { + resource: String, + }, + RawResourceDrop { + resource: String, + }, + RawResourceMethod { + resource: String, + method: String, + }, + RawResourceStaticMethod { + resource: String, + method: String, + }, + IndexedResourceConstructor { + resource: String, + resource_params: Vec, + }, + IndexedResourceMethod { + resource: String, + resource_params: Vec, + method: String, + }, + IndexedResourceStaticMethod { + resource: String, + resource_params: Vec, + method: String, + }, + IndexedResourceDrop { + resource: String, + resource_params: Vec, + }, +} + +impl DynamicParsedFunctionReference { + fn to_static(&self) -> ParsedFunctionReference { + match self { + Self::Function { function } => ParsedFunctionReference::Function { + function: function.clone(), + }, + Self::RawResourceConstructor { resource } => { + ParsedFunctionReference::RawResourceConstructor { + resource: resource.clone(), + } + } + Self::RawResourceDrop { resource } => ParsedFunctionReference::RawResourceDrop { + resource: resource.clone(), + }, + Self::RawResourceMethod { resource, method } => { + ParsedFunctionReference::RawResourceMethod { + resource: resource.clone(), + method: method.clone(), + } + } + Self::RawResourceStaticMethod { resource, method } => { + ParsedFunctionReference::RawResourceStaticMethod { + resource: resource.clone(), + method: method.clone(), + } + } + Self::IndexedResourceConstructor { + resource, + resource_params, + } => ParsedFunctionReference::IndexedResourceConstructor { + resource: resource.clone(), + resource_params: resource_params.iter().map(text::to_raw_string).collect(), + }, + Self::IndexedResourceMethod { + resource, + resource_params, + method, + } => ParsedFunctionReference::IndexedResourceMethod { + resource: resource.clone(), + resource_params: resource_params.iter().map(text::to_raw_string).collect(), + method: method.clone(), + }, + Self::IndexedResourceStaticMethod { + resource, + resource_params, + method, + } => ParsedFunctionReference::IndexedResourceStaticMethod { + resource: resource.clone(), + resource_params: resource_params.iter().map(text::to_raw_string).collect(), + method: method.clone(), + }, + Self::IndexedResourceDrop { + resource, + resource_params, + } => ParsedFunctionReference::IndexedResourceDrop { + resource: resource.clone(), + resource_params: resource_params.iter().map(text::to_raw_string).collect(), + }, + } + } + + pub fn raw_resource_params_mut(&mut self) -> Option<&mut Vec> { + match self { + Self::IndexedResourceConstructor { + resource_params, .. + } + | Self::IndexedResourceMethod { + resource_params, .. + } + | Self::IndexedResourceStaticMethod { + resource_params, .. + } + | Self::IndexedResourceDrop { + resource_params, .. + } => Some(resource_params), + _ => None, + } + } + + pub fn raw_resource_params(&self) -> Option<&Vec> { + match self { + Self::IndexedResourceConstructor { + resource_params, .. + } + | Self::IndexedResourceMethod { + resource_params, .. + } + | Self::IndexedResourceStaticMethod { + resource_params, .. + } + | Self::IndexedResourceDrop { + resource_params, .. + } => Some(resource_params), + _ => None, + } + } +} + impl Display for ParsedFunctionReference { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let function_name = match self { @@ -430,6 +569,143 @@ impl ParsedFunctionReference { } } +impl From + for golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference +{ + fn from(value: DynamicParsedFunctionReference) -> Self { + let function = match value { + DynamicParsedFunctionReference::Function { function } => ProtoDynamicFunctionReference::Function( + golem_api_grpc::proto::golem::rib::FunctionFunctionReference { function }, + ), + DynamicParsedFunctionReference::RawResourceConstructor { resource } => ProtoDynamicFunctionReference::RawResourceConstructor( + golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { resource }, + ), + DynamicParsedFunctionReference::RawResourceMethod { resource, method } => ProtoDynamicFunctionReference::RawResourceMethod( + golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { resource, method }, + ), + DynamicParsedFunctionReference::RawResourceStaticMethod { resource, method } => ProtoDynamicFunctionReference::RawResourceStaticMethod( + golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { resource, method }, + ), + DynamicParsedFunctionReference::RawResourceDrop { resource } => ProtoDynamicFunctionReference::RawResourceDrop( + golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { resource }, + ), + DynamicParsedFunctionReference::IndexedResourceConstructor { resource, resource_params } => ProtoDynamicFunctionReference::IndexedResourceConstructor( + golem_api_grpc::proto::golem::rib::DynamicIndexedResourceConstructorFunctionReference { + resource, + resource_params: resource_params.into_iter().map(|x| x.into()).collect(), + }, + ), + DynamicParsedFunctionReference::IndexedResourceMethod { resource, resource_params, method } => ProtoDynamicFunctionReference::IndexedResourceMethod( + golem_api_grpc::proto::golem::rib::DynamicIndexedResourceMethodFunctionReference { + resource, + resource_params: resource_params.into_iter().map(|x| x.into()).collect(), + method, + }, + ), + DynamicParsedFunctionReference::IndexedResourceStaticMethod { resource, resource_params, method } => ProtoDynamicFunctionReference::IndexedResourceStaticMethod( + golem_api_grpc::proto::golem::rib::DynamicIndexedResourceStaticMethodFunctionReference { + resource, + resource_params: resource_params.into_iter().map(|x| x.into()).collect(), + method, + }, + ), + DynamicParsedFunctionReference::IndexedResourceDrop { resource, resource_params } => ProtoDynamicFunctionReference::IndexedResourceDrop( + golem_api_grpc::proto::golem::rib::DynamicIndexedResourceDropFunctionReference { + resource, + resource_params: resource_params.into_iter().map(|x| x.into()).collect(), + }, + ), + }; + + golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference { + function_reference: Some(function), + } + } +} + +impl TryFrom + for DynamicParsedFunctionReference +{ + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference, + ) -> Result { + let function = value + .function_reference + .ok_or("Missing function reference".to_string())?; + + match function { + ProtoDynamicFunctionReference::Function(golem_api_grpc::proto::golem::rib::FunctionFunctionReference { + function + }) => { + Ok(Self::Function { function }) + }, + ProtoDynamicFunctionReference::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { + resource + }) => { + Ok(Self::RawResourceConstructor { resource }) + }, + ProtoDynamicFunctionReference::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { + resource, + method + }) => { + Ok(Self::RawResourceMethod { resource, method }) + }, + ProtoDynamicFunctionReference::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { + resource, + method + }) => { + Ok(Self::RawResourceStaticMethod { resource, method }) + }, + ProtoDynamicFunctionReference::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { + resource + }) => { + Ok(Self::RawResourceDrop { resource }) + }, + ProtoDynamicFunctionReference::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceConstructorFunctionReference { + resource, + resource_params + }) => { + + let resource_params: Vec = + resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; + + Ok(Self::IndexedResourceConstructor { resource, resource_params }) + }, + ProtoDynamicFunctionReference::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceMethodFunctionReference { + resource, + resource_params, + method + }) => { + let resource_params: Vec = + resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; + + Ok(Self::IndexedResourceMethod { resource, resource_params, method }) + }, + ProtoDynamicFunctionReference::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceStaticMethodFunctionReference { + resource, + resource_params, + method + }) => { + let resource_params: Vec = + resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; + + Ok(Self::IndexedResourceStaticMethod { resource, resource_params, method }) + }, + ProtoDynamicFunctionReference::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceDropFunctionReference { + resource, + resource_params + }) => { + let resource_params: Vec = + resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; + + Ok(Self::IndexedResourceDrop { resource, resource_params }) + }, + } + } +} + impl TryFrom for ParsedFunctionReference { @@ -598,6 +874,52 @@ pub struct ParsedFunctionName { pub function: ParsedFunctionReference, } +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +pub struct DynamicParsedFunctionName { + pub site: ParsedFunctionSite, + pub function: DynamicParsedFunctionReference, +} + +impl DynamicParsedFunctionName { + pub fn parse(name: impl AsRef) -> Result { + let name = name.as_ref(); + + let mut parser = crate::parser::call::function_name(); + + let result: Result<(DynamicParsedFunctionName, &str), easy::ParseError<&str>> = + parser.easy_parse(name); + + match result { + Ok((parsed, _)) => Ok(parsed), + Err(error) => { + let error_message = error + .map_position(|p| p.translate_position(name)) + .to_string(); + Err(error_message) + } + } + } + + pub fn function_name(&self) -> String { + self.to_static().function.function_name() + } + + // + pub fn to_static(&self) -> ParsedFunctionName { + ParsedFunctionName { + site: self.site.clone(), + function: self.function.to_static(), + } + } +} + +impl Display for DynamicParsedFunctionName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let function_name = self.to_static().to_string(); + write!(f, "{}", function_name) + } +} + impl Serialize for ParsedFunctionName { fn serialize(&self, serializer: S) -> Result { let function_name = self.to_string(); @@ -651,11 +973,11 @@ impl ParsedFunctionName { let mut parser = crate::parser::call::function_name(); - let result: Result<(ParsedFunctionName, &str), easy::ParseError<&str>> = + let result: Result<(DynamicParsedFunctionName, &str), easy::ParseError<&str>> = parser.easy_parse(name); match result { - Ok((parsed, _)) => Ok(parsed), + Ok((parsed, _)) => Ok(parsed.to_static()), Err(error) => { let error_message = error .map_position(|p| p.translate_position(name)) @@ -681,6 +1003,33 @@ impl ParsedFunctionName { } } +impl TryFrom + for DynamicParsedFunctionName +{ + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName, + ) -> Result { + let site = ParsedFunctionSite::try_from(value.site.ok_or("Missing site".to_string())?)?; + let function = DynamicParsedFunctionReference::try_from( + value.function.ok_or("Missing function".to_string())?, + )?; + Ok(Self { site, function }) + } +} + +impl From + for golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName +{ + fn from(value: DynamicParsedFunctionName) -> Self { + golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName { + site: Some(value.site.into()), + function: Some(value.function.into()), + } + } +} + impl TryFrom for ParsedFunctionName { type Error = String; @@ -943,7 +1292,7 @@ mod function_name_tests { parsed.function().raw_resource_params(), Some(&vec![ "\"hello\"".to_string(), - "{ field-a: some(1) }".to_string(), + "{field-a: some(1)}".to_string(), ]) ); assert_eq!( @@ -959,7 +1308,7 @@ mod function_name_tests { resource: "resource1".to_string(), resource_params: vec![ "\"hello\"".to_string(), - "{ field-a: some(1) }".to_string(), + "{field-a: some(1)}".to_string(), ], }, }, @@ -1209,7 +1558,7 @@ mod function_name_tests { parsed.function().raw_resource_params(), Some(&vec![ "\"hello\"".to_string(), - "{ field-a: some(1) }".to_string(), + "{field-a: some(1)}".to_string(), ]) ); assert_eq!( @@ -1225,7 +1574,7 @@ mod function_name_tests { resource: "resource1".to_string(), resource_params: vec![ "\"hello\"".to_string(), - "{ field-a: some(1) }".to_string(), + "{field-a: some(1)}".to_string(), ], }, }, diff --git a/golem-rib/src/inferred_type.rs b/golem-rib/src/inferred_type.rs index eba310a539..17188b3b74 100644 --- a/golem-rib/src/inferred_type.rs +++ b/golem-rib/src/inferred_type.rs @@ -793,7 +793,7 @@ impl InferredType { (InferredType::OneOf(types), inferred_type) => { let mut unified = None; for typ in types { - match typ.unify_with_required(inferred_type) { + match typ.unify_with_alternative(inferred_type) { Ok(result) => { unified = Some(result); break; diff --git a/golem-rib/src/interpreter/env.rs b/golem-rib/src/interpreter/env.rs index 6a33817bf3..8340887253 100644 --- a/golem-rib/src/interpreter/env.rs +++ b/golem-rib/src/interpreter/env.rs @@ -13,9 +13,10 @@ // limitations under the License. use crate::interpreter::result::RibInterpreterResult; -use crate::{ParsedFunctionName, VariableId}; +use crate::VariableId; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use std::collections::HashMap; +use std::fmt::Debug; use std::future::Future; use std::pin::Pin; use std::sync::Arc; @@ -25,9 +26,17 @@ pub struct InterpreterEnv { pub call_worker_function_async: RibFunctionInvoke, } +impl Debug for InterpreterEnv { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("InterpreterEnv") + .field("env", &self.env) + .finish() + } +} + pub type RibFunctionInvoke = Arc< dyn Fn( - ParsedFunctionName, + String, Vec, ) -> Pin> + Send>> + Send @@ -56,7 +65,7 @@ impl InterpreterEnv { pub fn invoke_worker_function_async( &self, - function_name: ParsedFunctionName, + function_name: String, args: Vec, ) -> Pin> + Send>> { (self.call_worker_function_async)(function_name, args) diff --git a/golem-rib/src/interpreter/rib_interpreter.rs b/golem-rib/src/interpreter/rib_interpreter.rs index 90c38928c6..0ab9b769ce 100644 --- a/golem-rib/src/interpreter/rib_interpreter.rs +++ b/golem-rib/src/interpreter/rib_interpreter.rs @@ -19,6 +19,7 @@ use crate::{RibByteCode, RibIR}; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use std::collections::{HashMap, VecDeque}; +#[derive(Debug)] pub struct Interpreter { pub stack: InterpreterStack, pub env: InterpreterEnv, @@ -135,8 +136,12 @@ impl Interpreter { internal::run_select_index_instruction(&mut self.stack, index)?; } - RibIR::InvokeFunction(parsed_function_name, arity, _) => { - internal::run_call_instruction(parsed_function_name, arity, self).await?; + RibIR::CreateFunctionName(site, function_type) => { + internal::run_create_function_name_instruction(site, function_type, self)?; + } + + RibIR::InvokeFunction(arity, _) => { + internal::run_call_instruction(arity, self).await?; } RibIR::PushVariant(variant_name, analysed_type) => { @@ -210,13 +215,16 @@ mod internal { use crate::interpreter::result::RibInterpreterResult; use crate::interpreter::stack::InterpreterStack; use crate::{ - GetLiteralValue, InstructionId, Interpreter, ParsedFunctionName, RibIR, VariableId, + FunctionReferenceType, GetLiteralValue, InstructionId, Interpreter, ParsedFunctionName, + ParsedFunctionReference, ParsedFunctionSite, RibIR, VariableId, }; use golem_wasm_ast::analysis::AnalysedType; use golem_wasm_ast::analysis::TypeResult; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use golem_wasm_rpc::protobuf::typed_result::ResultValue; use golem_wasm_rpc::protobuf::{NameValuePair, TypedRecord, TypedTuple}; + use golem_wasm_rpc::type_annotated_value_to_string; + use std::collections::VecDeque; use std::ops::Deref; @@ -350,6 +358,7 @@ mod internal { match analysed_type { AnalysedType::Tuple(inner_type) => { // Last updated value in stack should be a list to update the list + let last_list = interpreter_stack .pop_n(list_size) .ok_or(format!("Expected {} value on the stack", list_size))?; @@ -534,15 +543,13 @@ mod internal { let variant_arg_typ = variant.typ.clone(); - let arg_value = match variant_arg_typ { - Some(_) => Some( - interpreter - .stack - .pop_val() - .ok_or("Failed to get a value from the stack".to_string())?, - ), - None => None, - }; + let arg_value = + match variant_arg_typ { + Some(_) => Some(interpreter.stack.pop_val().ok_or( + "Failed to get the variant argument from the stack".to_string(), + )?), + None => None, + }; interpreter.stack.push_variant( variant_name.clone(), @@ -559,12 +566,208 @@ mod internal { } } + pub(crate) fn run_create_function_name_instruction( + site: ParsedFunctionSite, + function_type: FunctionReferenceType, + interpreter: &mut Interpreter, + ) -> Result<(), String> { + match function_type { + FunctionReferenceType::Function { function } => { + let parsed_function_name = ParsedFunctionName { + site, + function: ParsedFunctionReference::Function { function }, + }; + + interpreter + .stack + .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + } + + FunctionReferenceType::RawResourceConstructor { resource } => { + let parsed_function_name = ParsedFunctionName { + site, + function: ParsedFunctionReference::RawResourceConstructor { resource }, + }; + + interpreter + .stack + .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + } + FunctionReferenceType::RawResourceDrop { resource } => { + let parsed_function_name = ParsedFunctionName { + site, + function: ParsedFunctionReference::RawResourceDrop { resource }, + }; + + interpreter + .stack + .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + } + FunctionReferenceType::RawResourceMethod { resource, method } => { + let parsed_function_name = ParsedFunctionName { + site, + function: ParsedFunctionReference::RawResourceMethod { resource, method }, + }; + + interpreter + .stack + .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + } + FunctionReferenceType::RawResourceStaticMethod { resource, method } => { + let parsed_function_name = ParsedFunctionName { + site, + function: ParsedFunctionReference::RawResourceStaticMethod { resource, method }, + }; + + interpreter + .stack + .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + } + FunctionReferenceType::IndexedResourceConstructor { resource, arg_size } => { + let last_n_elements = interpreter + .stack + .pop_n(arg_size) + .ok_or("Failed to get values from the stack".to_string())?; + + let type_anntoated_values = last_n_elements + .iter() + .map(|interpreter_result| { + interpreter_result + .get_val() + .ok_or("Failed to get value from the stack".to_string()) + }) + .collect::, String>>()?; + + let parsed_function_name = ParsedFunctionName { + site, + function: ParsedFunctionReference::IndexedResourceConstructor { + resource, + resource_params: type_anntoated_values + .iter() + .map(type_annotated_value_to_string) + .collect::, String>>()?, + }, + }; + + interpreter + .stack + .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + } + FunctionReferenceType::IndexedResourceMethod { + resource, + arg_size, + method, + } => { + let last_n_elements = interpreter + .stack + .pop_n(arg_size) + .ok_or("Failed to get values from the stack".to_string())?; + + let type_anntoated_values = last_n_elements + .iter() + .map(|interpreter_result| { + interpreter_result + .get_val() + .ok_or("Failed to get value from the stack".to_string()) + }) + .collect::, String>>()?; + + let parsed_function_name = ParsedFunctionName { + site, + function: ParsedFunctionReference::IndexedResourceMethod { + resource, + resource_params: type_anntoated_values + .iter() + .map(type_annotated_value_to_string) + .collect::, String>>()?, + method, + }, + }; + + interpreter + .stack + .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + } + FunctionReferenceType::IndexedResourceStaticMethod { + resource, + arg_size, + method, + } => { + let last_n_elements = interpreter + .stack + .pop_n(arg_size) + .ok_or("Failed to get values from the stack".to_string())?; + + let type_anntoated_values = last_n_elements + .iter() + .map(|interpreter_result| { + interpreter_result + .get_val() + .ok_or("Failed to get value from the stack".to_string()) + }) + .collect::, String>>()?; + + let parsed_function_name = ParsedFunctionName { + site, + function: ParsedFunctionReference::IndexedResourceStaticMethod { + resource, + resource_params: type_anntoated_values + .iter() + .map(type_annotated_value_to_string) + .collect::, String>>()?, + method, + }, + }; + + interpreter + .stack + .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + } + FunctionReferenceType::IndexedResourceDrop { resource, arg_size } => { + let last_n_elements = interpreter + .stack + .pop_n(arg_size) + .ok_or("Failed to get values from the stack".to_string())?; + + let type_anntoated_values = last_n_elements + .iter() + .map(|interpreter_result| { + interpreter_result + .get_val() + .ok_or("Failed to get value from the stack".to_string()) + }) + .collect::, String>>()?; + + let parsed_function_name = ParsedFunctionName { + site, + function: ParsedFunctionReference::IndexedResourceDrop { + resource, + resource_params: type_anntoated_values + .iter() + .map(type_annotated_value_to_string) + .collect::, String>>()?, + }, + }; + + interpreter + .stack + .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + } + } + + Ok(()) + } + // Separate variant pub(crate) async fn run_call_instruction( - parsed_function_name: ParsedFunctionName, argument_size: usize, interpreter: &mut Interpreter, ) -> Result<(), String> { + let function_name = interpreter + .stack + .pop_str() + .ok_or("Failed to get a function name from the stack".to_string())?; + let last_n_elements = interpreter .stack .pop_n(argument_size) @@ -581,7 +784,7 @@ mod internal { let result = interpreter .env - .invoke_worker_function_async(parsed_function_name, type_anntoated_values) + .invoke_worker_function_async(function_name, type_anntoated_values) .await?; let interpreter_result = match result { @@ -779,7 +982,8 @@ mod interpreter_tests { use super::*; use crate::{compiler, Expr, FunctionTypeRegistry, InstructionId, VariableId}; use golem_wasm_ast::analysis::{ - AnalysedType, NameTypePair, TypeList, TypeRecord, TypeS32, TypeStr, + AnalysedType, NameOptionTypePair, NameTypePair, TypeF32, TypeList, TypeRecord, TypeS32, + TypeStr, TypeU32, TypeVariant, }; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use golem_wasm_rpc::protobuf::{NameValuePair, TypedList, TypedRecord}; @@ -1222,8 +1426,352 @@ mod interpreter_tests { ); } + #[tokio::test] + async fn test_interpreter_with_indexed_resource_drop() { + let expr = r#" + let user_id = "user"; + golem:it/api.{cart(user_id).drop}(); + "success" + "#; + let expr = Expr::from_text(expr).unwrap(); + let component_metadata = + internal::get_shopping_cart_metadata_with_cart_resource_with_parameters(); + + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_interpreter = Interpreter::default(); + let result = rib_interpreter.run(compiled.byte_code).await.unwrap(); + + assert_eq!( + result.get_val().unwrap(), + TypeAnnotatedValue::Str("success".to_string()) + ); + } + + #[tokio::test] + async fn test_interpreter_with_indexed_resource_checkout() { + let expr = r#" + let user_id = "foo"; + let result = golem:it/api.{cart(user_id).checkout}(); + result + "#; + + let expr = Expr::from_text(expr).unwrap(); + + let result_type = AnalysedType::Variant(TypeVariant { + cases: vec![ + NameOptionTypePair { + name: "error".to_string(), + typ: Some(AnalysedType::Str(TypeStr)), + }, + NameOptionTypePair { + name: "success".to_string(), + typ: Some(AnalysedType::Record(TypeRecord { + fields: vec![NameTypePair { + name: "order-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }], + })), + }, + ], + }); + + let result_value = internal::type_annotated_value_result( + &result_type, + r#" + success({order-id: "foo"}) + "#, + ); + + let component_metadata = + internal::get_shopping_cart_metadata_with_cart_resource_with_parameters(); + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_executor = internal::test_executor(&result_type, &result_value); + let result = rib_executor.run(compiled.byte_code).await.unwrap(); + + assert_eq!(result.get_val().unwrap(), result_value); + } + + #[tokio::test] + async fn test_interpreter_with_indexed_resource_get_cart_contents() { + let expr = r#" + let user_id = "bar"; + let result = golem:it/api.{cart(user_id).get-cart-contents}(); + result[0].product-id + "#; + + let expr = Expr::from_text(expr).unwrap(); + + let result_type = AnalysedType::List(TypeList { + inner: Box::new(AnalysedType::Record(TypeRecord { + fields: vec![ + NameTypePair { + name: "product-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + NameTypePair { + name: "name".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + NameTypePair { + name: "price".to_string(), + typ: AnalysedType::F32(TypeF32), + }, + NameTypePair { + name: "quantity".to_string(), + typ: AnalysedType::U32(TypeU32), + }, + ], + })), + }); + + let result_value = internal::type_annotated_value_result( + &result_type, + r#" + [{product-id: "foo", name: "bar", price: 100.0, quantity: 1}, {product-id: "bar", name: "baz", price: 200.0, quantity: 2}] + "#, + ); + + let component_metadata = + internal::get_shopping_cart_metadata_with_cart_resource_with_parameters(); + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_executor = internal::test_executor(&result_type, &result_value); + let result = rib_executor.run(compiled.byte_code).await.unwrap(); + + assert_eq!( + result.get_val().unwrap(), + TypeAnnotatedValue::Str("foo".to_string()) + ); + } + + #[tokio::test] + async fn test_interpreter_with_indexed_resource_update_item_quantity() { + let expr = r#" + let user_id = "jon"; + let product_id = "mac"; + let quantity = 1032; + golem:it/api.{cart(user_id).update-item-quantity}(product_id, quantity); + "successfully updated" + "#; + let expr = Expr::from_text(expr).unwrap(); + + let component_metadata = + internal::get_shopping_cart_metadata_with_cart_resource_with_parameters(); + + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_executor = Interpreter::default(); + + let result = rib_executor.run(compiled.byte_code).await.unwrap(); + + assert_eq!( + result.get_val().unwrap(), + TypeAnnotatedValue::Str("successfully updated".to_string()) + ); + } + + #[tokio::test] + async fn test_interpreter_with_indexed_resource_add_item() { + let expr = r#" + let user_id = "foo"; + let product = { product-id: "mac", name: "macbook", quantity: 1u32, price: 1f32 }; + golem:it/api.{cart(user_id).add-item}(product); + + "successfully added" + "#; + + let expr = Expr::from_text(expr).unwrap(); + + let component_metadata = + internal::get_shopping_cart_metadata_with_cart_resource_with_parameters(); + + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_executor = Interpreter::default(); + + let result = rib_executor.run(compiled.byte_code).await.unwrap(); + + assert_eq!( + result.get_val().unwrap(), + TypeAnnotatedValue::Str("successfully added".to_string()) + ); + } + + #[tokio::test] + async fn test_interpreter_with_resource_add_item() { + let expr = r#" + let user_id = "foo"; + let product = { product-id: "mac", name: "macbook", quantity: 1u32, price: 1f32 }; + golem:it/api.{cart.add-item}(product); + + "successfully added" + "#; + + let expr = Expr::from_text(expr).unwrap(); + + let component_metadata = internal::get_shopping_cart_metadata_with_cart_raw_resource(); + + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_executor = Interpreter::default(); + + let result = rib_executor.run(compiled.byte_code).await.unwrap(); + + assert_eq!( + result.get_val().unwrap(), + TypeAnnotatedValue::Str("successfully added".to_string()) + ); + } + + #[tokio::test] + async fn test_interpreter_with_resource_get_cart_contents() { + let expr = r#" + let result = golem:it/api.{cart.get-cart-contents}(); + result[0].product-id + "#; + + let expr = Expr::from_text(expr).unwrap(); + + let result_type = AnalysedType::List(TypeList { + inner: Box::new(AnalysedType::Record(TypeRecord { + fields: vec![ + NameTypePair { + name: "product-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + NameTypePair { + name: "name".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + NameTypePair { + name: "price".to_string(), + typ: AnalysedType::F32(TypeF32), + }, + NameTypePair { + name: "quantity".to_string(), + typ: AnalysedType::U32(TypeU32), + }, + ], + })), + }); + + let result_value = internal::type_annotated_value_result( + &result_type, + r#" + [{product-id: "foo", name: "bar", price: 100.0, quantity: 1}, {product-id: "bar", name: "baz", price: 200.0, quantity: 2}] + "#, + ); + + let component_metadata = internal::get_shopping_cart_metadata_with_cart_raw_resource(); + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_executor = internal::test_executor(&result_type, &result_value); + let result = rib_executor.run(compiled.byte_code).await.unwrap(); + + assert_eq!( + result.get_val().unwrap(), + TypeAnnotatedValue::Str("foo".to_string()) + ); + } + + #[tokio::test] + async fn test_interpreter_with_resource_update_item() { + let expr = r#" + let product_id = "mac"; + let quantity = 1032; + golem:it/api.{cart.update-item-quantity}(product_id, quantity); + "successfully updated" + "#; + let expr = Expr::from_text(expr).unwrap(); + + let component_metadata = internal::get_shopping_cart_metadata_with_cart_raw_resource(); + + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_executor = Interpreter::default(); + + let result = rib_executor.run(compiled.byte_code).await.unwrap(); + + assert_eq!( + result.get_val().unwrap(), + TypeAnnotatedValue::Str("successfully updated".to_string()) + ); + } + + #[tokio::test] + async fn test_interpreter_with_resource_checkout() { + let expr = r#" + let result = golem:it/api.{cart.checkout}(); + result + "#; + + let expr = Expr::from_text(expr).unwrap(); + + let result_type = AnalysedType::Variant(TypeVariant { + cases: vec![ + NameOptionTypePair { + name: "error".to_string(), + typ: Some(AnalysedType::Str(TypeStr)), + }, + NameOptionTypePair { + name: "success".to_string(), + typ: Some(AnalysedType::Record(TypeRecord { + fields: vec![NameTypePair { + name: "order-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }], + })), + }, + ], + }); + + let result_value = internal::type_annotated_value_result( + &result_type, + r#" + success({order-id: "foo"}) + "#, + ); + + let component_metadata = internal::get_shopping_cart_metadata_with_cart_raw_resource(); + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_executor = internal::test_executor(&result_type, &result_value); + let result = rib_executor.run(compiled.byte_code).await.unwrap(); + + assert_eq!(result.get_val().unwrap(), result_value); + } + + #[tokio::test] + async fn test_interpreter_with_resource_drop() { + let expr = r#" + golem:it/api.{cart.drop}(); + "success" + "#; + let expr = Expr::from_text(expr).unwrap(); + let component_metadata = internal::get_shopping_cart_metadata_with_cart_raw_resource(); + + let compiled = compiler::compile(&expr, &component_metadata).unwrap(); + + let mut rib_interpreter = Interpreter::default(); + let result = rib_interpreter.run(compiled.byte_code).await.unwrap(); + + assert_eq!( + result.get_val().unwrap(), + TypeAnnotatedValue::Str("success".to_string()) + ); + } + mod internal { + use crate::interpreter::env::InterpreterEnv; + use crate::interpreter::stack::InterpreterStack; + use crate::{Interpreter, RibFunctionInvoke}; use golem_wasm_ast::analysis::*; + use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_rpc::protobuf::TypedTuple; + use std::collections::HashMap; + use std::sync::Arc; pub(crate) fn get_analysed_type_variant() -> AnalysedType { AnalysedType::Variant(TypeVariant { @@ -1332,5 +1880,258 @@ mod interpreter_tests { }], })] } + + pub(crate) fn get_shopping_cart_metadata_with_cart_resource_with_parameters( + ) -> Vec { + get_shopping_cart_metadata_with_cart_resource(vec![AnalysedFunctionParameter { + name: "user-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }]) + } + + pub(crate) fn get_shopping_cart_metadata_with_cart_raw_resource() -> Vec { + get_shopping_cart_metadata_with_cart_resource(vec![]) + } + + fn get_shopping_cart_metadata_with_cart_resource( + constructor_parameters: Vec, + ) -> Vec { + let instance = AnalysedExport::Instance(AnalysedInstance { + name: "golem:it/api".to_string(), + functions: vec![ + AnalysedFunction { + name: "[constructor]cart".to_string(), + parameters: constructor_parameters, + results: vec![AnalysedFunctionResult { + name: None, + typ: AnalysedType::Handle(TypeHandle { + resource_id: AnalysedResourceId(0), + mode: AnalysedResourceMode::Owned, + }), + }], + }, + AnalysedFunction { + name: "[method]cart.add-item".to_string(), + parameters: vec![ + AnalysedFunctionParameter { + name: "self".to_string(), + typ: AnalysedType::Handle(TypeHandle { + resource_id: AnalysedResourceId(0), + mode: AnalysedResourceMode::Borrowed, + }), + }, + AnalysedFunctionParameter { + name: "item".to_string(), + typ: AnalysedType::Record(TypeRecord { + fields: vec![ + NameTypePair { + name: "product-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + NameTypePair { + name: "name".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + NameTypePair { + name: "price".to_string(), + typ: AnalysedType::F32(TypeF32), + }, + NameTypePair { + name: "quantity".to_string(), + typ: AnalysedType::U32(TypeU32), + }, + ], + }), + }, + ], + results: vec![], + }, + AnalysedFunction { + name: "[method]cart.remove-item".to_string(), + parameters: vec![ + AnalysedFunctionParameter { + name: "self".to_string(), + typ: AnalysedType::Handle(TypeHandle { + resource_id: AnalysedResourceId(0), + mode: AnalysedResourceMode::Borrowed, + }), + }, + AnalysedFunctionParameter { + name: "product-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + ], + results: vec![], + }, + AnalysedFunction { + name: "[method]cart.update-item-quantity".to_string(), + parameters: vec![ + AnalysedFunctionParameter { + name: "self".to_string(), + typ: AnalysedType::Handle(TypeHandle { + resource_id: AnalysedResourceId(0), + mode: AnalysedResourceMode::Borrowed, + }), + }, + AnalysedFunctionParameter { + name: "product-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + AnalysedFunctionParameter { + name: "quantity".to_string(), + typ: AnalysedType::U32(TypeU32), + }, + ], + results: vec![], + }, + AnalysedFunction { + name: "[method]cart.checkout".to_string(), + parameters: vec![AnalysedFunctionParameter { + name: "self".to_string(), + typ: AnalysedType::Handle(TypeHandle { + resource_id: AnalysedResourceId(0), + mode: AnalysedResourceMode::Borrowed, + }), + }], + results: vec![AnalysedFunctionResult { + name: None, + typ: AnalysedType::Variant(TypeVariant { + cases: vec![ + NameOptionTypePair { + name: "error".to_string(), + typ: Some(AnalysedType::Str(TypeStr)), + }, + NameOptionTypePair { + name: "success".to_string(), + typ: Some(AnalysedType::Record(TypeRecord { + fields: vec![NameTypePair { + name: "order-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }], + })), + }, + ], + }), + }], + }, + AnalysedFunction { + name: "[method]cart.get-cart-contents".to_string(), + parameters: vec![AnalysedFunctionParameter { + name: "self".to_string(), + typ: AnalysedType::Handle(TypeHandle { + resource_id: AnalysedResourceId(0), + mode: AnalysedResourceMode::Borrowed, + }), + }], + results: vec![AnalysedFunctionResult { + name: None, + typ: AnalysedType::List(TypeList { + inner: Box::new(AnalysedType::Record(TypeRecord { + fields: vec![ + NameTypePair { + name: "product-id".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + NameTypePair { + name: "name".to_string(), + typ: AnalysedType::Str(TypeStr), + }, + NameTypePair { + name: "price".to_string(), + typ: AnalysedType::F32(TypeF32), + }, + NameTypePair { + name: "quantity".to_string(), + typ: AnalysedType::U32(TypeU32), + }, + ], + })), + }), + }], + }, + AnalysedFunction { + name: "[method]cart.merge-with".to_string(), + parameters: vec![ + AnalysedFunctionParameter { + name: "self".to_string(), + typ: AnalysedType::Handle(TypeHandle { + resource_id: AnalysedResourceId(0), + mode: AnalysedResourceMode::Borrowed, + }), + }, + AnalysedFunctionParameter { + name: "other-cart".to_string(), + typ: AnalysedType::Handle(TypeHandle { + resource_id: AnalysedResourceId(0), + mode: AnalysedResourceMode::Borrowed, + }), + }, + ], + results: vec![], + }, + AnalysedFunction { + name: "[drop]cart".to_string(), + parameters: vec![AnalysedFunctionParameter { + name: "self".to_string(), + typ: AnalysedType::Handle(TypeHandle { + resource_id: AnalysedResourceId(0), + mode: AnalysedResourceMode::Owned, + }), + }], + results: vec![], + }, + ], + }); + + vec![instance] + } + + pub(crate) fn type_annotated_value_result( + analysed_type: &AnalysedType, + wasm_wave_str: &str, + ) -> TypeAnnotatedValue { + golem_wasm_rpc::type_annotated_value_from_str(analysed_type, wasm_wave_str).unwrap() + } + + pub(crate) fn test_executor( + result_type: &AnalysedType, + result_value: &TypeAnnotatedValue, + ) -> Interpreter { + Interpreter { + stack: InterpreterStack::default(), + env: InterpreterEnv { + env: HashMap::new(), + call_worker_function_async: static_worker_invoke(result_type, result_value), + }, + } + } + + fn static_worker_invoke( + result_type: &AnalysedType, + value: &TypeAnnotatedValue, + ) -> RibFunctionInvoke { + let analysed_type = result_type.clone(); + let value = value.clone(); + + Arc::new(move |_, _| { + Box::pin({ + let analysed_type = analysed_type.clone(); + let value = value.clone(); + + async move { + let analysed_type = analysed_type.clone(); + let value = value.clone(); + Ok(TypeAnnotatedValue::Tuple(TypedTuple { + typ: vec![golem_wasm_ast::analysis::protobuf::Type::from( + &analysed_type, + )], + value: vec![golem_wasm_rpc::protobuf::TypeAnnotatedValue { + type_annotated_value: Some(value.clone()), + }], + })) + } + }) + }) + } } } diff --git a/golem-rib/src/interpreter/stack.rs b/golem-rib/src/interpreter/stack.rs index eda6ef4de9..385ba0246e 100644 --- a/golem-rib/src/interpreter/stack.rs +++ b/golem-rib/src/interpreter/stack.rs @@ -20,7 +20,7 @@ use golem_wasm_rpc::protobuf::{ TypedEnum, TypedList, TypedOption, TypedRecord, TypedTuple, TypedVariant, }; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct InterpreterStack { pub stack: Vec, } @@ -63,6 +63,13 @@ impl InterpreterStack { Some(results) } + pub fn pop_str(&mut self) -> Option { + self.pop_val().and_then(|v| match v { + TypeAnnotatedValue::Str(s) => Some(s), + _ => None, + }) + } + pub fn pop_val(&mut self) -> Option { self.stack.pop().and_then(|v| v.get_val()) } diff --git a/golem-rib/src/parser/binary_comparison.rs b/golem-rib/src/parser/binary_comparison.rs index cc8a63eb46..aa51c1173f 100644 --- a/golem-rib/src/parser/binary_comparison.rs +++ b/golem-rib/src/parser/binary_comparison.rs @@ -12,59 +12,51 @@ // See the License for the specific language governing permissions and // limitations under the License. -use combine::parser::char::{spaces, string}; -use combine::{attempt, choice, ParseError, Parser}; - -use crate::expr::Expr; use crate::parser::errors::RibParseError; -use crate::InferredType; +use combine::parser::char::string; +use combine::{attempt, choice, ParseError, Parser}; -pub fn binary( - left_expr: impl Parser, - right_expr: impl Parser, -) -> impl Parser +pub fn binary_op() -> impl Parser where Input: combine::Stream, RibParseError: Into< >::StreamError, >, { - spaces().with( - ( - left_expr.skip(spaces()), - choice(( - attempt(string(">=")), - attempt(string("<=")), - string("<"), - string(">"), - string("=="), - )) - .skip(spaces()), - right_expr.skip(spaces()), - ) - .message("Expected a valid expression of the form x > y") - .map(|(left, str, right)| match str { - ">" => Expr::GreaterThan(Box::new(left), Box::new(right), InferredType::Bool), - "<" => Expr::LessThan(Box::new(left), Box::new(right), InferredType::Bool), - "==" => Expr::EqualTo(Box::new(left), Box::new(right), InferredType::Bool), - ">=" => { - Expr::GreaterThanOrEqualTo(Box::new(left), Box::new(right), InferredType::Bool) - } - "<=" => { - Expr::LessThanOrEqualTo(Box::new(left), Box::new(right), InferredType::Bool) - } - _ => unreachable!(), - }), - ) + choice(( + attempt(string(">=")), + attempt(string("<=")), + attempt(string("==")), + string("<"), + string(">"), + )) + .and_then(|str| match str { + ">" => Ok(BinaryOp::GreaterThan), + "<" => Ok(BinaryOp::LessThan), + "==" => Ok(BinaryOp::EqualTo), + ">=" => Ok(BinaryOp::GreaterThanOrEqualTo), + "<=" => Ok(BinaryOp::LessThanOrEqualTo), + _ => Err(RibParseError::Message( + "Invalid binary operator".to_string(), + )), + }) +} + +pub enum BinaryOp { + GreaterThan, + LessThan, + LessThanOrEqualTo, + GreaterThanOrEqualTo, + EqualTo, } #[cfg(test)] mod test { - use combine::EasyParser; - use crate::parser::rib_expr::rib_expr; - - use super::*; + use crate::{ + DynamicParsedFunctionName, DynamicParsedFunctionReference, Expr, ParsedFunctionSite, + }; + use combine::EasyParser; #[test] fn test_greater_than() { @@ -163,4 +155,170 @@ mod test { )) ); } + + #[test] + fn test_binary_op_of_record() { + let input = "{foo : 1} == {foo: 2}"; + let result = rib_expr().easy_parse(input); + assert_eq!( + result, + Ok(( + Expr::equal_to( + Expr::record(vec![("foo".to_string(), Expr::number(1f64))]), + Expr::record(vec![("foo".to_string(), Expr::number(2f64))]), + ), + "" + )) + ); + } + + #[test] + fn test_binary_op_of_sequence() { + let input = "[1, 2] == [3, 4]"; + let result = rib_expr().easy_parse(input); + assert_eq!( + result, + Ok(( + Expr::equal_to( + Expr::sequence(vec![Expr::number(1f64), Expr::number(2f64)]), + Expr::sequence(vec![Expr::number(3f64), Expr::number(4f64)]), + ), + "" + )) + ); + } + + #[test] + fn test_binary_op_of_tuple() { + let input = "(1, 2) == (3, 4)"; + let result = rib_expr().easy_parse(input); + assert_eq!( + result, + Ok(( + Expr::equal_to( + Expr::tuple(vec![Expr::number(1f64), Expr::number(2f64)]), + Expr::tuple(vec![Expr::number(3f64), Expr::number(4f64)]), + ), + "" + )) + ); + } + + #[test] + fn test_binary_op_of_select_field() { + let input = "foo.bar == baz.qux"; + let result = rib_expr().easy_parse(input); + assert_eq!( + result, + Ok(( + Expr::equal_to( + Expr::select_field(Expr::identifier("foo"), "bar"), + Expr::select_field(Expr::identifier("baz"), "qux"), + ), + "" + )) + ); + } + + #[test] + fn test_binary_op_of_select_index() { + let input = "foo[1] == bar[2]"; + let result = rib_expr().easy_parse(input); + assert_eq!( + result, + Ok(( + Expr::equal_to( + Expr::select_index(Expr::identifier("foo"), 1), + Expr::select_index(Expr::identifier("bar"), 2), + ), + "" + )) + ); + } + + #[test] + fn test_binary_op_of_result() { + let input = "ok(foo) == ok(bar)"; + let result = rib_expr().easy_parse(input); + assert_eq!( + result, + Ok(( + Expr::equal_to( + Expr::ok(Expr::identifier("foo")), + Expr::ok(Expr::identifier("bar")), + ), + "" + )) + ); + } + + #[test] + fn test_binary_op_of_option() { + let input = "some(foo) == some(bar)"; + let result = rib_expr().easy_parse(input); + assert_eq!( + result, + Ok(( + Expr::equal_to( + Expr::option(Some(Expr::identifier("foo"))), + Expr::option(Some(Expr::identifier("bar"))), + ), + "" + )) + ); + } + + #[test] + fn test_binary_op_of_call() { + let input = "foo() == bar()"; + let result = rib_expr().easy_parse(input); + assert_eq!( + result, + Ok(( + Expr::equal_to( + Expr::call( + DynamicParsedFunctionName { + site: ParsedFunctionSite::Global, + function: DynamicParsedFunctionReference::Function { + function: "foo".to_string(), + } + }, + vec![] + ), + Expr::call( + DynamicParsedFunctionName { + site: ParsedFunctionSite::Global, + function: DynamicParsedFunctionReference::Function { + function: "bar".to_string(), + } + }, + vec![] + ), + ), + "" + )) + ); + } + + #[test] + fn test_binary_op_in_record() { + let input = "{foo: bar > baz, baz: bar == foo}"; + let result = rib_expr().easy_parse(input); + assert_eq!( + result, + Ok(( + Expr::record(vec![ + ( + "foo".to_string(), + Expr::greater_than(Expr::identifier("bar"), Expr::identifier("baz")) + ), + ( + "baz".to_string(), + Expr::equal_to(Expr::identifier("bar"), Expr::identifier("foo")) + ), + ]), + "" + )) + ); + } } diff --git a/golem-rib/src/parser/call.rs b/golem-rib/src/parser/call.rs index d07c6e18b8..b29012c38d 100644 --- a/golem-rib/src/parser/call.rs +++ b/golem-rib/src/parser/call.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::{DynamicParsedFunctionName, DynamicParsedFunctionReference}; use combine::error::Commit; use combine::parser::char::{alpha_num, string}; use combine::parser::char::{char, spaces}; @@ -20,9 +21,7 @@ use combine::sep_by; use combine::{any, attempt, between, choice, many1, optional, parser, token, ParseError, Parser}; use crate::expr::Expr; -use crate::function_name::{ - ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite, SemVer, -}; +use crate::function_name::{ParsedFunctionSite, SemVer}; use crate::parser::errors::RibParseError; use crate::parser::rib_expr::rib_expr; @@ -46,11 +45,7 @@ where .message("Invalid function call") } -// TODO; Reusing function_name between Rib and internals of GOLEM may be a surface level requirement -// as users can form function name in various other ways. -// Example: Arguments to a resource can be partial because they may come from request parameters -// and these are not represented using the current structure of ParsedFunctionName -pub fn function_name() -> impl Parser +pub fn function_name() -> impl Parser where Input: combine::Stream, RibParseError: Into< @@ -81,7 +76,10 @@ where nesting += 1; current_param.push(next_char); } else if next_char == ',' && nesting == 1 { - result.push(current_param.trim().to_string()); + let expr = + Expr::from_text(current_param.trim()).expect("Failed to parse expression"); + + result.push(expr); current_param.clear(); } else { current_param.push(next_char); @@ -94,7 +92,9 @@ where } if !current_param.is_empty() { - result.push(current_param.trim().to_string()); + let expr = + Expr::from_text(current_param.trim()).expect("Failed to parse expression"); + result.push(expr); } Ok((result, result_committed.unwrap())) @@ -112,44 +112,55 @@ where }) .message("version"); - let single_function = identifier().map(|id| ParsedFunctionReference::Function { function: id }); + let single_function = + identifier().map(|id| DynamicParsedFunctionReference::Function { function: id }); let indexed_resource_syntax = || (identifier(), token('(').with(capture_resource_params())); let indexed_constructor_syntax = (indexed_resource_syntax(), token('.'), string("new")).map( - |((resource, resource_params), _, _)| ParsedFunctionReference::IndexedResourceConstructor { - resource, - resource_params, + |((resource, resource_params), _, _)| { + DynamicParsedFunctionReference::IndexedResourceConstructor { + resource, + resource_params, + } }, ); let indexed_drop_syntax = (indexed_resource_syntax(), token('.'), string("drop")).map( - |((resource, resource_params), _, _)| ParsedFunctionReference::IndexedResourceDrop { + |((resource, resource_params), _, _)| DynamicParsedFunctionReference::IndexedResourceDrop { resource, resource_params, }, ); let indexed_method_syntax = (indexed_resource_syntax(), token('.'), identifier()).map( - |((resource, resource_params), _, method)| ParsedFunctionReference::IndexedResourceMethod { - resource, - resource_params, - method, + |((resource, resource_params), _, method)| { + DynamicParsedFunctionReference::IndexedResourceMethod { + resource, + resource_params, + method, + } }, ); let raw_constructor_syntax = (identifier(), token('.'), string("new")) - .map(|(resource, _, _)| ParsedFunctionReference::RawResourceConstructor { resource }) - .or((string("[constructor]"), identifier()) - .map(|(_, resource)| ParsedFunctionReference::RawResourceConstructor { resource })); + .map(|(resource, _, _)| DynamicParsedFunctionReference::RawResourceConstructor { resource }) + .or( + (string("[constructor]"), identifier()).map(|(_, resource)| { + DynamicParsedFunctionReference::RawResourceConstructor { resource } + }), + ); let raw_drop_syntax = (identifier(), token('.'), string("drop")) - .map(|(resource, _, _)| ParsedFunctionReference::RawResourceDrop { resource }) + .map(|(resource, _, _)| DynamicParsedFunctionReference::RawResourceDrop { resource }) .or((string("[drop]"), identifier()) - .map(|(_, resource)| ParsedFunctionReference::RawResourceDrop { resource })); + .map(|(_, resource)| DynamicParsedFunctionReference::RawResourceDrop { resource })); let raw_method_syntax = (identifier(), token('.'), identifier()) .map( - |(resource, _, method)| ParsedFunctionReference::RawResourceMethod { resource, method }, + |(resource, _, method)| DynamicParsedFunctionReference::RawResourceMethod { + resource, + method, + }, ) .or( (string("[method]"), identifier(), token('.'), identifier()).map( - |(_, resource, _, method)| ParsedFunctionReference::RawResourceMethod { + |(_, resource, _, method)| DynamicParsedFunctionReference::RawResourceMethod { resource, method, }, @@ -157,7 +168,7 @@ where ); let raw_static_method_syntax = (string("[static]"), identifier(), token('.'), identifier()) .map( - |(_, resource, _, method)| ParsedFunctionReference::RawResourceStaticMethod { + |(_, resource, _, method)| DynamicParsedFunctionReference::RawResourceStaticMethod { resource, method, }, @@ -194,23 +205,21 @@ where }, None => ParsedFunctionSite::Interface { name: iface }, }; - ParsedFunctionName { site, function } + DynamicParsedFunctionName { site, function } }), ) - .or(identifier().map(|id| ParsedFunctionName { + .or(identifier().map(|id| DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { function: id }, + function: DynamicParsedFunctionReference::Function { function: id }, })) } - #[cfg(test)] mod function_call_tests { + use crate::{DynamicParsedFunctionName, DynamicParsedFunctionReference}; use combine::EasyParser; use crate::expr::Expr; - use crate::function_name::{ - ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite, SemVer, - }; + use crate::function_name::{ParsedFunctionSite, SemVer}; use crate::parser::rib_expr::rib_expr; #[test] @@ -219,9 +228,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -240,9 +249,9 @@ mod function_call_tests { let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -259,9 +268,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -278,9 +287,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -301,9 +310,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -325,9 +334,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -350,9 +359,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -376,9 +385,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -398,9 +407,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -420,9 +429,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -442,9 +451,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -465,9 +474,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -487,9 +496,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -509,9 +518,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -531,9 +540,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -553,9 +562,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -575,9 +584,9 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }, @@ -594,11 +603,11 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::Interface { name: "interface".to_string(), }, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "fn1".to_string(), }, }, @@ -615,14 +624,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "fn1".to_string(), }, }, @@ -639,14 +648,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "wasi".to_string(), package: "cli".to_string(), interface: "run".to_string(), version: Some(SemVer(semver::Version::new(0, 2, 0))), }, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "run".to_string(), }, }, @@ -663,14 +672,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::RawResourceConstructor { + function: DynamicParsedFunctionReference::RawResourceConstructor { resource: "resource1".to_string(), }, }, @@ -687,14 +696,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::RawResourceConstructor { + function: DynamicParsedFunctionReference::RawResourceConstructor { resource: "resource1".to_string(), }, }, @@ -711,14 +720,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::IndexedResourceConstructor { + function: DynamicParsedFunctionReference::IndexedResourceConstructor { resource: "resource1".to_string(), resource_params: vec![], }, @@ -738,19 +747,19 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::IndexedResourceConstructor { + function: DynamicParsedFunctionReference::IndexedResourceConstructor { resource: "resource1".to_string(), resource_params: vec![ - "\"hello\"".to_string(), - "1".to_string(), - "true".to_string(), + Expr::literal("hello"), + Expr::number(1f64), + Expr::boolean(true), ], }, }, @@ -768,18 +777,21 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::IndexedResourceConstructor { + function: DynamicParsedFunctionReference::IndexedResourceConstructor { resource: "resource1".to_string(), resource_params: vec![ - "\"hello\"".to_string(), - "{ field-a: some(1) }".to_string(), + Expr::literal("hello"), + Expr::record(vec![( + "field-a".to_string(), + Expr::option(Some(Expr::number(1f64))), + )]), ], }, }, @@ -795,14 +807,14 @@ mod function_call_tests { let input = "ns:name/interface.{resource1.do-something}({bar, baz})"; let result = Expr::from_text(input).unwrap(); let expected = Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::RawResourceMethod { + function: DynamicParsedFunctionReference::RawResourceMethod { resource: "resource1".to_string(), method: "do-something".to_string(), }, @@ -818,14 +830,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::RawResourceMethod { + function: DynamicParsedFunctionReference::RawResourceMethod { resource: "resource1".to_string(), method: "do-something".to_string(), }, @@ -844,14 +856,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::RawResourceMethod { + function: DynamicParsedFunctionReference::RawResourceMethod { resource: "resource1".to_string(), method: "do-something-static".to_string(), }, @@ -869,14 +881,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::RawResourceStaticMethod { + function: DynamicParsedFunctionReference::RawResourceStaticMethod { resource: "resource1".to_string(), method: "do-something-static".to_string(), }, @@ -894,14 +906,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::RawResourceDrop { + function: DynamicParsedFunctionReference::RawResourceDrop { resource: "resource1".to_string(), }, }, @@ -918,14 +930,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::IndexedResourceDrop { + function: DynamicParsedFunctionReference::IndexedResourceDrop { resource: "resource1".to_string(), resource_params: vec![], }, @@ -943,19 +955,19 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::IndexedResourceDrop { + function: DynamicParsedFunctionReference::IndexedResourceDrop { resource: "resource1".to_string(), resource_params: vec![ - "\"hello\"".to_string(), - "1".to_string(), - "true".to_string(), + Expr::literal("hello"), + Expr::number(1f64), + Expr::boolean(true), ], }, }, @@ -973,18 +985,21 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::IndexedResourceDrop { + function: DynamicParsedFunctionReference::IndexedResourceDrop { resource: "resource1".to_string(), resource_params: vec![ - "\"hello\"".to_string(), - "{ field-a: some(1) }".to_string(), + Expr::literal("hello"), + Expr::record(vec![( + "field-a".to_string(), + Expr::option(Some(Expr::number(1f64))), + )]), ], }, }, @@ -1001,14 +1016,14 @@ mod function_call_tests { let result = rib_expr().easy_parse(input); let expected = Ok(( Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: ParsedFunctionSite::PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: ParsedFunctionReference::RawResourceDrop { + function: DynamicParsedFunctionReference::RawResourceDrop { resource: "resource1".to_string(), }, }, diff --git a/golem-rib/src/parser/multi_line_code_block.rs b/golem-rib/src/parser/multi_line_code_block.rs index 07b7dca8d9..11cf775271 100644 --- a/golem-rib/src/parser/multi_line_code_block.rs +++ b/golem-rib/src/parser/multi_line_code_block.rs @@ -67,7 +67,8 @@ mod internal { #[cfg(test)] mod tests { use crate::expr::Expr; - use crate::{ArmPattern, MatchArm, ParsedFunctionName}; + use crate::function_name::DynamicParsedFunctionName; + use crate::{ArmPattern, MatchArm}; #[test] fn test_block_parse() { @@ -86,11 +87,11 @@ mod tests { Expr::let_binding("x", Expr::number(1f64)), Expr::let_binding("y", Expr::number(2f64)), Expr::call( - ParsedFunctionName::parse("foo").unwrap(), + DynamicParsedFunctionName::parse("foo").unwrap(), vec![Expr::identifier("x")], ), Expr::call( - ParsedFunctionName::parse("foo").unwrap(), + DynamicParsedFunctionName::parse("foo").unwrap(), vec![Expr::identifier("y")], ), ]); @@ -117,11 +118,11 @@ mod tests { Expr::let_binding("x", Expr::number(1f64)), Expr::let_binding("y", Expr::number(2f64)), Expr::call( - ParsedFunctionName::parse("foo").unwrap(), + DynamicParsedFunctionName::parse("foo").unwrap(), vec![Expr::identifier("x")], ), Expr::call( - ParsedFunctionName::parse("foo").unwrap(), + DynamicParsedFunctionName::parse("foo").unwrap(), vec![Expr::identifier("y")], ), ]), @@ -154,11 +155,11 @@ mod tests { Expr::let_binding("x", Expr::number(1f64)), Expr::let_binding("y", Expr::number(2f64)), Expr::call( - ParsedFunctionName::parse("foo").unwrap(), + DynamicParsedFunctionName::parse("foo").unwrap(), vec![Expr::identifier("x")], ), Expr::call( - ParsedFunctionName::parse("foo").unwrap(), + DynamicParsedFunctionName::parse("foo").unwrap(), vec![Expr::identifier("y")], ), ]), @@ -194,11 +195,11 @@ mod tests { Expr::let_binding("x", Expr::number(1f64)), Expr::let_binding("y", Expr::number(2f64)), Expr::call( - ParsedFunctionName::parse("foo").unwrap(), + DynamicParsedFunctionName::parse("foo").unwrap(), vec![Expr::identifier("x")], ), Expr::call( - ParsedFunctionName::parse("foo").unwrap(), + DynamicParsedFunctionName::parse("foo").unwrap(), vec![Expr::identifier("y")], ), ]), diff --git a/golem-rib/src/parser/rib_expr.rs b/golem-rib/src/parser/rib_expr.rs index 8d1f8b2f9f..fc3350e306 100644 --- a/golem-rib/src/parser/rib_expr.rs +++ b/golem-rib/src/parser/rib_expr.rs @@ -14,36 +14,16 @@ use combine::parser::char; use combine::parser::char::{char, spaces}; -use combine::parser::choice::choice; -use combine::{attempt, eof, ParseError, Parser, Stream}; +use combine::{eof, ParseError, Parser}; use combine::{parser, sep_by}; use crate::expr::Expr; -use crate::parser::boolean::boolean_literal; -use crate::parser::call::call; use crate::parser::errors::RibParseError; -use crate::parser::identifier::identifier; -use crate::parser::literal::literal; -use crate::parser::multi_line_code_block::multi_line_block; -use crate::parser::not::not; -use crate::parser::sequence::sequence; -use super::binary_comparison::binary; -use super::cond::conditional; -use super::flag::flag; -use super::let_binding::let_binding; -use super::number::number; -use super::optional::option; -use super::pattern_match::pattern_match; -use super::record::record; -use super::result::result; -use super::select_field::select_field; -use super::select_index::select_index; -use super::tuple::tuple; +use super::binary_comparison::BinaryOp; -// Parse a full Rib Program. -// This is kept outside for a reason, to avoid the conditions that lead to stack over-flow -// Please don't refactor and inline this with `parser!` macros below. +// Parse a full Rib Program, and we expect the parser to fully consume the stream +// unlike rib block expression pub fn rib_program() -> impl Parser where Input: combine::Stream, @@ -64,10 +44,7 @@ where ) } -// To handle recursion based on docs -// Also note that, the immediate parsers on the sides of a binary expression can result in stack overflow -// Therefore we copy the parser without these binary parsers in the attempt list to build the binary comparison parsers. -// This may not be intuitive however will work! +// A rib expression := (simple_expr, rib_expr_rest*) parser! { pub fn rib_expr[Input]()(Input) -> Expr where [Input: combine::Stream, RibParseError: Into<>::StreamError>,] @@ -84,100 +61,122 @@ where >, { spaces() - .with(choice(( - pattern_match(), - let_binding(), - conditional(), - binary_rib(), - selection_expr(), - flag_or_record(), - multi_line_block(), - tuple(), - sequence(), - boolean_literal(), - literal(), - not(), - option(), - result(), - attempt(call()), - identifier(), - number(), - ))) + .with( + (internal::simple_expr(), internal::rib_expr_rest()).map(|(expr, rest)| { + // FIXME: Respect operator precedence + rest.into_iter().fold(expr, |acc, (op, next)| match op { + BinaryOp::GreaterThan => Expr::greater_than(acc, next), + BinaryOp::LessThan => Expr::less_than(acc, next), + BinaryOp::LessThanOrEqualTo => Expr::less_than_or_equal_to(acc, next), + BinaryOp::GreaterThanOrEqualTo => Expr::greater_than_or_equal_to(acc, next), + BinaryOp::EqualTo => Expr::equal_to(acc, next), + }) + }), + ) .skip(spaces()) } -pub fn binary_rib() -> impl Parser -where - Input: combine::Stream, - RibParseError: Into< - >::StreamError, - >, -{ - attempt(binary(comparison_operands(), comparison_operands())) -} +mod internal { + use crate::parser::binary_comparison::{binary_op, BinaryOp}; + use crate::parser::boolean::boolean_literal; + use crate::parser::call::call; + use crate::parser::cond::conditional; + use crate::parser::errors::RibParseError; + use crate::parser::flag::flag; + use crate::parser::identifier::identifier; + use crate::parser::let_binding::let_binding; + use crate::parser::literal::literal; + use crate::parser::multi_line_code_block::multi_line_block; + use crate::parser::not::not; + use crate::parser::number::number; + use crate::parser::optional::option; + use crate::parser::pattern_match::pattern_match; + use crate::parser::record::record; + use crate::parser::result::result; -pub fn flag_or_record() -> impl Parser -where - Input: combine::Stream, - RibParseError: Into< - >::StreamError, - >, -{ - choice((attempt(flag()), attempt(record()))).message("Unable to parse flag or record") -} + use crate::parser::select_field::select_field; + use crate::parser::select_index::select_index; + use crate::parser::sequence::sequence; + use crate::parser::tuple::tuple; + use crate::Expr; + use combine::parser::char::spaces; + use combine::{attempt, choice, many, parser, ParseError, Parser, Stream}; -fn selection_expr_() -> impl Parser -where - Input: combine::Stream, - RibParseError: Into< - >::StreamError, - >, -{ - choice((attempt(select_field()), attempt(select_index()))) - .message("Unable to parse selection expression") -} - -parser! { - fn selection_expr[Input]()(Input) -> Expr - where [Input: Stream, RibParseError: Into<>::StreamError>,] + // A simple expression is a composition of all parsers that doesn't involve left recursion + pub fn simple_expr_() -> impl Parser + where + Input: combine::Stream, + RibParseError: Into< + >::StreamError, + >, { - selection_expr_() + spaces() + .with(choice(( + pattern_match(), + let_binding(), + conditional(), + selection_expr(), + flag_or_record(), + multi_line_block(), + tuple(), + sequence(), + boolean_literal(), + literal(), + not(), + option(), + result(), + attempt(call()), + identifier(), + number(), + ))) + .skip(spaces()) } -} -fn simple_expr_() -> impl Parser -where - Input: combine::Stream, - RibParseError: Into< - >::StreamError, - >, -{ - choice((literal(), not(), number(), boolean_literal(), identifier())) -} + parser! { + pub(crate) fn simple_expr[Input]()(Input) -> Expr + where [Input: Stream, RibParseError: Into<>::StreamError>,] + { + simple_expr_() + } + } -parser! { - fn simple_expr[Input]()(Input) -> Expr - where [Input: Stream, RibParseError: Into<>::StreamError>,] + pub fn rib_expr_rest_() -> impl Parser> + where + Input: combine::Stream, + RibParseError: Into< + >::StreamError, + >, { - simple_expr_() + many((binary_op(), simple_expr())) } -} -fn comparison_operands_() -> impl Parser -where - Input: combine::Stream, - RibParseError: Into< - >::StreamError, - >, -{ - selection_expr().or(simple_expr()) -} + parser! { + pub(crate) fn rib_expr_rest[Input]()(Input) -> Vec<(BinaryOp, Expr)> + where [Input: Stream, RibParseError: Into<>::StreamError>,] + { + rib_expr_rest_() + } + } -parser! { - fn comparison_operands[Input]()(Input) -> Expr - where [Input: Stream, RibParseError: Into<>::StreamError>,] + fn flag_or_record() -> impl Parser + where + Input: combine::Stream, + RibParseError: Into< + >::StreamError, + >, + { + choice((attempt(flag()), attempt(record()))).message("Unable to parse flag or record") + } + + fn selection_expr() -> impl Parser + where + Input: combine::Stream, + RibParseError: Into< + >::StreamError, + >, { - comparison_operands_() + choice((attempt(select_field()), attempt(select_index()))) + .message("Unable to parse selection expression") } } @@ -187,9 +186,8 @@ mod tests { use crate::expr::ArmPattern; use crate::expr::MatchArm; - use crate::function_name::ParsedFunctionName; - use crate::function_name::ParsedFunctionReference::RawResourceStaticMethod; use crate::function_name::ParsedFunctionSite::PackagedInterface; + use crate::function_name::{DynamicParsedFunctionName, DynamicParsedFunctionReference}; use super::*; @@ -265,14 +263,14 @@ mod tests { Expr::let_binding( "result", Expr::call( - ParsedFunctionName { + DynamicParsedFunctionName { site: PackagedInterface { namespace: "ns".to_string(), package: "name".to_string(), interface: "interface".to_string(), version: None, }, - function: RawResourceStaticMethod { + function: DynamicParsedFunctionReference::RawResourceStaticMethod { resource: "resource1".to_string(), method: "do-something-static".to_string(), }, diff --git a/golem-rib/src/text/mod.rs b/golem-rib/src/text/mod.rs index 18565ce3b7..0c00550393 100644 --- a/golem-rib/src/text/mod.rs +++ b/golem-rib/src/text/mod.rs @@ -26,6 +26,14 @@ pub fn to_string(expr: &Expr) -> Result { writer::write_expr(expr) } +// TODO; Once we avoid interpolation support +// we can remove this function and use `to_string`. +// Currently `to_string` writes expressions wrapped with interpolation +// unless they are literals/text concatenated string +pub fn to_raw_string(expr: &Expr) -> String { + writer::write_expr_without_interpolation(expr).unwrap() +} + #[cfg(test)] mod record_tests { use crate::expr::*; diff --git a/golem-rib/src/text/writer.rs b/golem-rib/src/text/writer.rs index 9db0afae23..0e61945f1c 100644 --- a/golem-rib/src/text/writer.rs +++ b/golem-rib/src/text/writer.rs @@ -41,6 +41,15 @@ pub fn write_expr(expr: &Expr) -> Result { Ok(String::from_utf8(buf).unwrap_or_else(|err| panic!("invalid UTF-8: {err:?}"))) } +pub fn write_expr_without_interpolation(expr: &Expr) -> Result { + let mut buf = vec![]; + let mut writer = Writer::new(&mut buf); + + writer.write_expr(expr)?; + + Ok(String::from_utf8(buf).unwrap_or_else(|err| panic!("invalid UTF-8: {err:?}"))) +} + struct Writer { inner: W, } diff --git a/golem-rib/src/type_inference/expr_visitor.rs b/golem-rib/src/type_inference/expr_visitor.rs index 5750f16c10..0f7ea5d142 100644 --- a/golem-rib/src/type_inference/expr_visitor.rs +++ b/golem-rib/src/type_inference/expr_visitor.rs @@ -1,3 +1,4 @@ +use crate::call_type::CallType; use crate::Expr; use std::collections::VecDeque; use std::ops::Deref; @@ -50,7 +51,13 @@ pub fn visit_children_bottom_up_mut<'a>(expr: &'a mut Expr, queue: &mut VecDeque Expr::Option(Some(expr), _) => queue.push_back(&mut *expr), Expr::Result(Ok(expr), _) => queue.push_back(&mut *expr), Expr::Result(Err(expr), _) => queue.push_back(&mut *expr), - Expr::Call(_, expressions, _) => queue.extend(expressions.iter_mut()), + Expr::Call(call_type, arguments, _) => { + if let Some(exprs) = internal::get_expressions_in_call_mut(call_type) { + queue.extend(exprs.iter_mut()) + } + + queue.extend(arguments.iter_mut()) + } Expr::Unwrap(expr, _) => queue.push_back(&mut *expr), // not yet needed Expr::And(expr1, expr2, _) => { queue.push_back(&mut *expr1); @@ -114,7 +121,14 @@ pub fn visit_children_bottom_up<'a>(expr: &'a Expr, queue: &mut VecDeque<&'a Exp Expr::Option(Some(expr), _) => queue.push_back(expr), Expr::Result(Ok(expr), _) => queue.push_back(expr), Expr::Result(Err(expr), _) => queue.push_back(expr), - Expr::Call(_, expressions, _) => queue.extend(expressions.iter()), + Expr::Call(call_type, arguments, _) => { + if let CallType::Function(dynamic) = call_type { + if let Some(params) = dynamic.function.raw_resource_params() { + queue.extend(params.iter()) + } + } + queue.extend(arguments.iter()) + } Expr::Unwrap(expr, _) => queue.push_back(expr), Expr::And(expr1, expr2, _) => { queue.push_back(expr1); @@ -203,8 +217,14 @@ pub fn visit_children_mut_top_down<'a>(expr: &'a mut Expr, queue: &mut VecDeque< Expr::Option(Some(expr), _) => queue.push_front(&mut *expr), Expr::Result(Ok(expr), _) => queue.push_front(&mut *expr), Expr::Result(Err(expr), _) => queue.push_front(&mut *expr), - Expr::Call(_, expressions, _) => { - for expr in expressions.iter_mut() { + Expr::Call(call_type, arguments, _) => { + if let Some(exprs) = internal::get_expressions_in_call_mut(call_type) { + for expr in exprs.iter_mut() { + queue.push_front(expr); + } + } + + for expr in arguments.iter_mut() { queue.push_front(expr); } } @@ -219,3 +239,18 @@ pub fn visit_children_mut_top_down<'a>(expr: &'a mut Expr, queue: &mut VecDeque< Expr::GetTag(_, _) => {} } } + +mod internal { + use crate::call_type::CallType; + use crate::Expr; + + pub(crate) fn get_expressions_in_call_mut(call_type: &mut CallType) -> Option<&mut Vec> { + match call_type { + CallType::Function(dynamic_parsed_function_name) => dynamic_parsed_function_name + .function + .raw_resource_params_mut(), + + _ => None, + } + } +} diff --git a/golem-rib/src/type_inference/function_type_inference.rs b/golem-rib/src/type_inference/function_type_inference.rs index 364501eab1..484d195eca 100644 --- a/golem-rib/src/type_inference/function_type_inference.rs +++ b/golem-rib/src/type_inference/function_type_inference.rs @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::type_registry::{FunctionTypeRegistry, RegistryKey, RegistryValue}; -use crate::{Expr, InferredType}; +use crate::type_registry::FunctionTypeRegistry; +use crate::Expr; use std::collections::VecDeque; pub fn infer_function_types( @@ -25,40 +25,12 @@ pub fn infer_function_types( while let Some(expr) = queue.pop_back() { match expr { Expr::Call(parsed_fn_name, args, inferred_type) => { - let key = RegistryKey::from_invocation_name(parsed_fn_name); - if let Some(value) = function_type_registry.types.get(&key) { - match value { - RegistryValue::Value(_) => {} - RegistryValue::Function { - parameter_types, - return_types, - } => { - if parameter_types.len() == args.len() { - for (arg, param_type) in args.iter_mut().zip(parameter_types) { - internal::check_function_arguments(param_type, arg)?; - arg.add_infer_type_mut(param_type.clone().into()); - arg.push_types_down()? - } - *inferred_type = { - if return_types.len() == 1 { - return_types[0].clone().into() - } else { - InferredType::Sequence( - return_types.iter().map(|t| t.clone().into()).collect(), - ) - } - } - } else { - return Err(format!( - "Function {} expects {} arguments, but {} were provided", - parsed_fn_name, - parameter_types.len(), - args.len() - )); - } - } - } - } + internal::resolve_call_expressions( + parsed_fn_name, + function_type_registry, + args, + inferred_type, + )?; } _ => expr.visit_children_mut_bottom_up(&mut queue), } @@ -68,8 +40,156 @@ pub fn infer_function_types( } mod internal { - use crate::Expr; + use crate::call_type::CallType; + use crate::{ + Expr, FunctionTypeRegistry, InferredType, ParsedFunctionName, RegistryKey, RegistryValue, + }; use golem_wasm_ast::analysis::AnalysedType; + use std::fmt::Display; + + pub(crate) fn resolve_call_expressions( + call_type: &mut CallType, + function_type_registry: &FunctionTypeRegistry, + args: &mut [Expr], + inferred_type: &mut InferredType, + ) -> Result<(), String> { + match call_type { + CallType::Function(dynamic_parsed_function_name) => { + let parsed_function_static = dynamic_parsed_function_name.clone().to_static(); + let function = parsed_function_static.clone().function; + if function.resource_name().is_some() { + let constructor_name = { + let raw_str = function.resource_name().ok_or("Resource name not found")?; + format!["[constructor]{}", raw_str] + }; + + let mut constructor_params: &mut Vec = &mut vec![]; + + if let Some(resource_params) = dynamic_parsed_function_name + .function + .raw_resource_params_mut() + { + constructor_params = resource_params + } + + let registry_key = RegistryKey::from_function_name( + &parsed_function_static.site, + constructor_name.as_str(), + ); + + // Infer the types of constructor parameter expressions + infer_types( + &FunctionNameInternal::ResourceConstructorName(constructor_name), + function_type_registry, + registry_key, + constructor_params, + inferred_type, + )?; + + // Infer the types of resource method parameters + let resource_method_name = function.function_name(); + let registry_key = RegistryKey::from_function_name( + &parsed_function_static.site, + resource_method_name.as_str(), + ); + + infer_types( + &FunctionNameInternal::ResourceMethodName(resource_method_name), + function_type_registry, + registry_key, + args, + inferred_type, + ) + } else { + let registry_key = RegistryKey::from_invocation_name(call_type); + infer_types( + &FunctionNameInternal::Fqn(parsed_function_static), + function_type_registry, + registry_key, + args, + inferred_type, + ) + } + } + + _ => Ok(()), + } + } + + fn infer_types( + function_name: &FunctionNameInternal, + function_type_registry: &FunctionTypeRegistry, + key: RegistryKey, + args: &mut [Expr], + inferred_type: &mut InferredType, + ) -> Result<(), String> { + if let Some(value) = function_type_registry.types.get(&key) { + match value { + RegistryValue::Value(_) => {} + RegistryValue::Function { + parameter_types, + return_types, + } => { + let mut parameter_types = parameter_types.clone(); + + if let FunctionNameInternal::ResourceMethodName(_) = function_name { + if let Some(AnalysedType::Handle(_)) = parameter_types.first() { + parameter_types.remove(0); + } + } + + if parameter_types.len() == args.len() { + for (arg, param_type) in args.iter_mut().zip(parameter_types) { + check_function_arguments(¶m_type, arg)?; + arg.add_infer_type_mut(param_type.clone().into()); + arg.push_types_down()? + } + + *inferred_type = { + if return_types.len() == 1 { + return_types[0].clone().into() + } else { + InferredType::Sequence( + return_types.iter().map(|t| t.clone().into()).collect(), + ) + } + } + } else { + return Err(format!( + "Function {} expects {} arguments, but {} were provided", + function_name, + parameter_types.len(), + args.len() + )); + } + } + } + } + + Ok(()) + } + + enum FunctionNameInternal { + ResourceConstructorName(String), + ResourceMethodName(String), + Fqn(ParsedFunctionName), + } + + impl Display for FunctionNameInternal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + FunctionNameInternal::ResourceConstructorName(name) => { + write!(f, "{}", name) + } + FunctionNameInternal::ResourceMethodName(name) => { + write!(f, "{}", name) + } + FunctionNameInternal::Fqn(name) => { + write!(f, "{}", name) + } + } + } + } // A preliminary check of the arguments passed before typ inference pub(crate) fn check_function_arguments( @@ -249,11 +369,9 @@ mod internal { #[cfg(test)] mod function_parameters_inference_tests { use crate::call_type::CallType; + use crate::function_name::{DynamicParsedFunctionName, DynamicParsedFunctionReference}; use crate::type_registry::FunctionTypeRegistry; - use crate::{ - Expr, InferredType, ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite, - VariableId, - }; + use crate::{Expr, InferredType, ParsedFunctionSite, VariableId}; use golem_wasm_ast::analysis::{ AnalysedExport, AnalysedFunction, AnalysedFunctionParameter, AnalysedType, TypeU32, TypeU64, }; @@ -295,9 +413,9 @@ mod function_parameters_inference_tests { let let_binding = Expr::let_binding("x", Expr::number(1f64)); let call_expr = Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), diff --git a/golem-rib/src/type_inference/mod.rs b/golem-rib/src/type_inference/mod.rs index c5b8f5b6a9..38cd59b858 100644 --- a/golem-rib/src/type_inference/mod.rs +++ b/golem-rib/src/type_inference/mod.rs @@ -52,11 +52,9 @@ mod type_inference_tests { mod let_binding_tests { use crate::call_type::CallType; + use crate::function_name::{DynamicParsedFunctionName, DynamicParsedFunctionReference}; use crate::type_inference::type_inference_tests::internal; - use crate::{ - Expr, InferredType, Number, ParsedFunctionName, ParsedFunctionReference, - ParsedFunctionSite, VariableId, - }; + use crate::{Expr, InferredType, Number, ParsedFunctionSite, VariableId}; #[test] fn test_simple_let_binding_type_inference() { @@ -83,9 +81,9 @@ mod type_inference_tests { ); let call_expr = Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), @@ -140,9 +138,9 @@ mod type_inference_tests { ); let call_expr1 = Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), @@ -154,9 +152,9 @@ mod type_inference_tests { ); let call_expr2 = Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "baz".to_string(), }, }), @@ -1019,11 +1017,12 @@ mod type_inference_tests { } mod pattern_match_tests { use crate::call_type::CallType; + use crate::function_name::{DynamicParsedFunctionName, DynamicParsedFunctionReference}; use crate::parser::type_name::TypeName; use crate::type_inference::type_inference_tests::internal; use crate::{ ArmPattern, Expr, FunctionTypeRegistry, InferredType, MatchArm, Number, - ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite, VariableId, + ParsedFunctionSite, VariableId, }; #[test] @@ -1076,9 +1075,9 @@ mod type_inference_tests { InferredType::U64, ))), Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), @@ -1096,9 +1095,9 @@ mod type_inference_tests { InferredType::U64, // because predicate is u64 ))), Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "baz".to_string(), }, }), @@ -1886,10 +1885,11 @@ mod type_inference_tests { } mod internal { use crate::call_type::CallType; + use crate::function_name::{DynamicParsedFunctionName, DynamicParsedFunctionReference}; use crate::parser::type_name::TypeName; use crate::{ ArmPattern, Expr, FunctionTypeRegistry, InferredType, MatchArm, MatchIdentifier, - ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite, VariableId, + ParsedFunctionSite, VariableId, }; use golem_wasm_ast::analysis::TypeVariant; use golem_wasm_ast::analysis::{ @@ -2063,9 +2063,9 @@ mod type_inference_tests { VariableId::local("result", 0), None, Box::new(Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "process".to_string(), }, }), @@ -2546,9 +2546,9 @@ mod type_inference_tests { VariableId::local("result", 0), None, Box::new(Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), diff --git a/golem-rib/src/type_inference/name_binding.rs b/golem-rib/src/type_inference/name_binding.rs index 08613afbbe..e8cc50ef94 100644 --- a/golem-rib/src/type_inference/name_binding.rs +++ b/golem-rib/src/type_inference/name_binding.rs @@ -74,10 +74,8 @@ mod internal { #[cfg(test)] mod name_binding_tests { use crate::call_type::CallType; - use crate::{ - Expr, InferredType, ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite, - VariableId, - }; + use crate::function_name::{DynamicParsedFunctionName, DynamicParsedFunctionReference}; + use crate::{Expr, InferredType, ParsedFunctionSite, VariableId}; #[test] fn test_name_binding_simple() { @@ -99,9 +97,9 @@ mod name_binding_tests { ); let call_expr = Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), @@ -146,9 +144,9 @@ mod name_binding_tests { ); let call_expr1 = Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), @@ -160,9 +158,9 @@ mod name_binding_tests { ); let call_expr2 = Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), @@ -207,9 +205,9 @@ mod name_binding_tests { ); let call_expr1 = Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), @@ -221,9 +219,9 @@ mod name_binding_tests { ); let call_expr2 = Expr::Call( - CallType::Function(ParsedFunctionName { + CallType::Function(DynamicParsedFunctionName { site: ParsedFunctionSite::Global, - function: ParsedFunctionReference::Function { + function: DynamicParsedFunctionReference::Function { function: "foo".to_string(), }, }), diff --git a/golem-rib/src/type_inference/type_pull_up.rs b/golem-rib/src/type_inference/type_pull_up.rs index 54331fbdca..2fc0ebb79c 100644 --- a/golem-rib/src/type_inference/type_pull_up.rs +++ b/golem-rib/src/type_inference/type_pull_up.rs @@ -246,7 +246,8 @@ mod internal { #[cfg(test)] mod type_pull_up_tests { - use crate::{ArmPattern, Expr, InferredType, Number, ParsedFunctionName}; + use crate::function_name::DynamicParsedFunctionName; + use crate::{ArmPattern, Expr, InferredType, Number}; #[test] pub fn test_pull_up_identifier() { @@ -403,7 +404,7 @@ mod type_pull_up_tests { #[test] pub fn test_pull_up_for_call() { let mut expr = Expr::call( - ParsedFunctionName::parse("global_fn").unwrap(), + DynamicParsedFunctionName::parse("global_fn").unwrap(), vec![Expr::number(1f64)], ); expr.pull_types_up().unwrap(); diff --git a/golem-rib/src/type_registry.rs b/golem-rib/src/type_registry.rs index 0fccf8de31..dad0f6a04f 100644 --- a/golem-rib/src/type_registry.rs +++ b/golem-rib/src/type_registry.rs @@ -13,6 +13,7 @@ // limitations under the License. use crate::call_type::CallType; +use crate::ParsedFunctionSite; use golem_wasm_ast::analysis::AnalysedExport; use golem_wasm_ast::analysis::AnalysedType; use std::collections::{HashMap, HashSet}; @@ -38,17 +39,26 @@ pub enum RegistryKey { } impl RegistryKey { + pub fn from_function_name(site: &ParsedFunctionSite, function_name: &str) -> RegistryKey { + match site.interface_name() { + None => RegistryKey::FunctionName(function_name.to_string()), + Some(name) => RegistryKey::FunctionNameWithInterface { + interface_name: name.to_string(), + function_name: function_name.to_string(), + }, + } + } pub fn from_invocation_name(invocation_name: &CallType) -> RegistryKey { match invocation_name { CallType::VariantConstructor(variant_name) => { RegistryKey::VariantName(variant_name.clone()) } CallType::EnumConstructor(enum_name) => RegistryKey::EnumName(enum_name.clone()), - CallType::Function(function_name) => match function_name.site().interface_name() { - None => RegistryKey::FunctionName(function_name.function().function_name()), + CallType::Function(function_name) => match function_name.site.interface_name() { + None => RegistryKey::FunctionName(function_name.function_name()), Some(interface_name) => RegistryKey::FunctionNameWithInterface { interface_name: interface_name.to_string(), - function_name: function_name.function().function_name(), + function_name: function_name.function_name(), }, }, } @@ -64,7 +74,7 @@ pub enum RegistryValue { }, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct FunctionTypeRegistry { pub types: HashMap, } diff --git a/golem-worker-executor-base/src/durable_host/clocks/monotonic_clock.rs b/golem-worker-executor-base/src/durable_host/clocks/monotonic_clock.rs index 25311cf61d..a5c4995a63 100644 --- a/golem-worker-executor-base/src/durable_host/clocks/monotonic_clock.rs +++ b/golem-worker-executor-base/src/durable_host/clocks/monotonic_clock.rs @@ -18,6 +18,7 @@ use wasmtime::component::Resource; use crate::durable_host::serialized::SerializableError; use crate::durable_host::{Durability, DurableWorkerCtx}; use crate::metrics::wasm::record_host_function_call; +use crate::services::oplog::CommitLevel; use crate::workerctx::WorkerCtx; use golem_common::model::oplog::WrappedFunctionType; use wasmtime_wasi::bindings::clocks::monotonic_clock::{Duration, Host, Instant, Pollable}; @@ -64,7 +65,7 @@ impl Host for DurableWorkerCtx { |ctx| Box::pin(async { Host::now(&mut ctx.as_wasi_view()).await }), ) .await?; - self.state.oplog.commit().await; + self.state.oplog.commit(CommitLevel::DurableOnly).await; let when = now.saturating_add(when); Host::subscribe_instant(&mut self.as_wasi_view(), when).await } diff --git a/golem-worker-executor-base/src/durable_host/durability.rs b/golem-worker-executor-base/src/durable_host/durability.rs index 975b0ff48d..91f5ce9481 100644 --- a/golem-worker-executor-base/src/durable_host/durability.rs +++ b/golem-worker-executor-base/src/durable_host/durability.rs @@ -15,7 +15,7 @@ use crate::durable_host::DurableWorkerCtx; use crate::error::GolemError; use crate::model::PersistenceLevel; -use crate::services::oplog::OplogOps; +use crate::services::oplog::{CommitLevel, OplogOps}; use crate::workerctx::WorkerCtx; use async_trait::async_trait; use bincode::{Decode, Encode}; @@ -342,7 +342,7 @@ impl DurableWorkerCtx { WrappedFunctionType::WriteRemoteBatched(_) ) { - self.state.oplog.commit().await; + self.state.oplog.commit(CommitLevel::DurableOnly).await; } } Ok(()) diff --git a/golem-worker-executor-base/src/durable_host/golem/mod.rs b/golem-worker-executor-base/src/durable_host/golem/mod.rs index 6dbf910af5..0b22cd0ddd 100644 --- a/golem-worker-executor-base/src/durable_host/golem/mod.rs +++ b/golem-worker-executor-base/src/durable_host/golem/mod.rs @@ -33,11 +33,14 @@ use crate::preview2::golem::api::host::{ ComponentVersion, HostGetWorkers, PersistenceLevel, RetryPolicy, UpdateMode, Uri, WorkerMetadata, }; +use crate::services::oplog::CommitLevel; use crate::services::HasWorker; -use crate::workerctx::{StatusManagement, WorkerCtx}; +use crate::workerctx::{InvocationManagement, StatusManagement, WorkerCtx}; use golem_common::model::oplog::{OplogEntry, OplogIndex, WrappedFunctionType}; use golem_common::model::regions::OplogRegion; -use golem_common::model::{ComponentId, OwnedWorkerId, PromiseId, ScanCursor, WorkerId}; +use golem_common::model::{ + ComponentId, IdempotencyKey, OwnedWorkerId, PromiseId, ScanCursor, WorkerId, +}; #[async_trait] impl HostGetWorkers for DurableWorkerCtx { @@ -420,7 +423,7 @@ impl golem::api::host::Host for DurableWorkerCtx { record_host_function_call("golem::api", "set_oplog_persistence_level"); // commit all pending entries and change persistence level if self.state.is_live() { - self.state.oplog.commit().await; + self.state.oplog.commit(CommitLevel::DurableOnly).await; } self.state.persistence_level = new_persistence_level.into(); debug!( @@ -446,13 +449,22 @@ impl golem::api::host::Host for DurableWorkerCtx { async fn generate_idempotency_key(&mut self) -> anyhow::Result { let _permit = self.begin_async_host_function().await?; record_host_function_call("golem::api", "generate_idempotency_key"); + + let current_idempotency_key = self + .get_current_idempotency_key() + .await + .unwrap_or(IdempotencyKey::fresh()); + let oplog_index = self.state.current_oplog_index().await; + + // NOTE: Now that IdempotencyKey::derived is used, we no longer need to persist this, but we do to avoid breaking existing oplogs let uuid = Durability::::custom_wrap( self, WrappedFunctionType::WriteRemote, "golem api::generate_idempotency_key", |_ctx| { Box::pin(async move { - let uuid = Uuid::new_v4(); + let key = IdempotencyKey::derived(¤t_idempotency_key, oplog_index); + let uuid = Uuid::parse_str(&key.value.to_string()).unwrap(); // this is guaranteed to be a uuid Ok::(uuid) }) }, diff --git a/golem-worker-executor-base/src/durable_host/http/types.rs b/golem-worker-executor-base/src/durable_host/http/types.rs index 5ec0fd7f4e..60abae5fde 100644 --- a/golem-worker-executor-base/src/durable_host/http/types.rs +++ b/golem-worker-executor-base/src/durable_host/http/types.rs @@ -43,7 +43,7 @@ use crate::durable_host::{Durability, DurableWorkerCtx, HttpRequestCloseOwner}; use crate::get_oplog_entry; use crate::metrics::wasm::record_host_function_call; use crate::model::PersistenceLevel; -use crate::services::oplog::OplogOps; +use crate::services::oplog::{CommitLevel, OplogOps}; use crate::workerctx::WorkerCtx; impl HostFields for DurableWorkerCtx { @@ -657,7 +657,7 @@ impl HostFutureIncomingResponse for DurableWorkerCtx { ) .await .unwrap_or_else(|err| panic!("failed to serialize http response: {err}")); - self.state.oplog.commit().await; + self.state.oplog.commit(CommitLevel::DurableOnly).await; } if !matches!(serializable_response, SerializableResponse::Pending) { diff --git a/golem-worker-executor-base/src/durable_host/mod.rs b/golem-worker-executor-base/src/durable_host/mod.rs index b933337ffc..07d9d95796 100644 --- a/golem-worker-executor-base/src/durable_host/mod.rs +++ b/golem-worker-executor-base/src/durable_host/mod.rs @@ -71,7 +71,7 @@ use wasmtime_wasi_http::{HttpResult, WasiHttpCtx, WasiHttpView}; use crate::durable_host::io::{ManagedStdErr, ManagedStdIn, ManagedStdOut}; use crate::durable_host::wasm_rpc::UrnExtensions; use crate::metrics::wasm::{record_number_of_replayed_functions, record_resume_worker}; -use crate::services::oplog::{Oplog, OplogOps, OplogService}; +use crate::services::oplog::{CommitLevel, Oplog, OplogOps, OplogService}; use crate::services::rpc::Rpc; use crate::services::scheduler::SchedulerService; use crate::services::HasOplogService; @@ -712,9 +712,10 @@ impl StatusManagement for DurableWorkerCtx { async fn store_worker_status(&self, status: WorkerStatus) { self.update_worker_status(|s| s.status = status.clone()) .await; - if status == WorkerStatus::Idle + if (status == WorkerStatus::Idle || status == WorkerStatus::Failed - || status == WorkerStatus::Exited + || status == WorkerStatus::Exited) + && self.component_metadata().component_type == ComponentType::Durable { debug!("Scheduling oplog archive"); let at = Utc::now().add(self.state.config.oplog.archive_interval); @@ -770,7 +771,7 @@ impl InvocationHooks for DurableWorkerCtx { self.worker_id() ) }); - self.state.oplog.commit().await; + self.state.oplog.commit(CommitLevel::Always).await; } Ok(()) } @@ -860,7 +861,7 @@ impl InvocationHooks for DurableWorkerCtx { .unwrap_or_else(|err| { panic!("could not encode function result for {full_function_name}: {err}") }); - self.state.oplog.commit().await; + self.state.oplog.commit(CommitLevel::Always).await; let oplog_idx = self.state.oplog.current_oplog_index().await; if let Some(idempotency_key) = self.state.get_current_idempotency_key() { diff --git a/golem-worker-executor-base/src/durable_host/wasm_rpc/mod.rs b/golem-worker-executor-base/src/durable_host/wasm_rpc/mod.rs index 72a25b46ef..d0b4eff5e3 100644 --- a/golem-worker-executor-base/src/durable_host/wasm_rpc/mod.rs +++ b/golem-worker-executor-base/src/durable_host/wasm_rpc/mod.rs @@ -21,9 +21,9 @@ use crate::error::GolemError; use crate::get_oplog_entry; use crate::metrics::wasm::record_host_function_call; use crate::model::PersistenceLevel; -use crate::services::oplog::OplogOps; +use crate::services::oplog::{CommitLevel, OplogOps}; use crate::services::rpc::{RpcDemand, RpcError}; -use crate::workerctx::WorkerCtx; +use crate::workerctx::{InvocationManagement, WorkerCtx}; use anyhow::anyhow; use async_trait::async_trait; use golem_common::model::oplog::{OplogEntry, WrappedFunctionType}; @@ -50,9 +50,9 @@ impl HostWasmRpc for DurableWorkerCtx { match location.parse_as_golem_urn() { Some((remote_worker_id, None)) => { - let remote_worker_id = remote_worker_id - .try_into_worker_id() - .ok_or(anyhow!("Must specify a worker name"))?; // TODO: this should not be a requirement here + let remote_worker_id = + generate_unique_local_worker_id(self, remote_worker_id).await?; + let remote_worker_id = OwnedWorkerId::new(&self.owned_worker_id.account_id, &remote_worker_id); let demand = self.rpc().create_demand(&remote_worker_id).await; @@ -87,13 +87,21 @@ impl HostWasmRpc for DurableWorkerCtx { let payload = entry.payload.downcast_ref::().unwrap(); let remote_worker_id = payload.remote_worker_id.clone(); + let current_idempotency_key = self + .get_current_idempotency_key() + .await + .unwrap_or(IdempotencyKey::fresh()); + let oplog_index = self.state.current_oplog_index().await; + + // NOTE: Now that IdempotencyKey::derived is used, we no longer need to persist this, but we do to avoid breaking existing oplogs let uuid = Durability::::custom_wrap( self, WrappedFunctionType::ReadLocal, "golem::rpc::wasm-rpc::invoke-and-await idempotency key", |_ctx| { Box::pin(async move { - let uuid = Uuid::new_v4(); + let key = IdempotencyKey::derived(¤t_idempotency_key, oplog_index); + let uuid = Uuid::parse_str(&key.value.to_string()).unwrap(); // this is guaranteed to be a uuid Ok::(uuid) }) }, @@ -152,13 +160,21 @@ impl HostWasmRpc for DurableWorkerCtx { let payload = entry.payload.downcast_ref::().unwrap(); let remote_worker_id = payload.remote_worker_id.clone(); + let current_idempotency_key = self + .get_current_idempotency_key() + .await + .unwrap_or(IdempotencyKey::fresh()); + let oplog_index = self.state.current_oplog_index().await; + + // NOTE: Now that IdempotencyKey::derived is used, we no longer need to persist this, but we do to avoid breaking existing oplogs let uuid = Durability::::custom_wrap( self, WrappedFunctionType::ReadLocal, "golem::rpc::wasm-rpc::invoke-and-await idempotency key", |_ctx| { Box::pin(async move { - let uuid = Uuid::new_v4(); + let key = IdempotencyKey::derived(¤t_idempotency_key, oplog_index); + let uuid = Uuid::parse_str(&key.value.to_string()).unwrap(); // this is guaranteed to be a uuid Ok::(uuid) }) }, @@ -221,13 +237,21 @@ impl HostWasmRpc for DurableWorkerCtx { let payload = entry.payload.downcast_ref::().unwrap(); let remote_worker_id = payload.remote_worker_id.clone(); + let current_idempotency_key = self + .get_current_idempotency_key() + .await + .unwrap_or(IdempotencyKey::fresh()); + let oplog_index = self.state.current_oplog_index().await; + + // NOTE: Now that IdempotencyKey::derived is used, we no longer need to persist this, but we do to avoid breaking existing oplogs let uuid = Durability::::custom_wrap( self, WrappedFunctionType::ReadLocal, "golem::rpc::wasm-rpc::invoke-and-await idempotency key", |_ctx| { Box::pin(async move { - let uuid = Uuid::new_v4(); + let key = IdempotencyKey::derived(¤t_idempotency_key, oplog_index); + let uuid = Uuid::parse_str(&key.value.to_string()).unwrap(); // this is guaranteed to be a uuid Ok::(uuid) }) }, @@ -479,7 +503,7 @@ impl HostFutureInvokeResult for DurableWorkerCtx { } } } - self.state.oplog.commit().await; + self.state.oplog.commit(CommitLevel::DurableOnly).await; } result @@ -539,6 +563,31 @@ impl HostFutureInvokeResult for DurableWorkerCtx { #[async_trait] impl golem_wasm_rpc::Host for DurableWorkerCtx {} +async fn generate_unique_local_worker_id( + ctx: &mut DurableWorkerCtx, + remote_worker_id: TargetWorkerId, +) -> Result { + match remote_worker_id.clone().try_into_worker_id() { + Some(worker_id) => Ok(worker_id), + None => { + let worker_id = Durability::::wrap( + ctx, + WrappedFunctionType::ReadLocal, + "golem::rpc::wasm-rpc::generate_unique_local_worker_id", + |ctx| { + Box::pin(async move { + ctx.rpc() + .generate_unique_local_worker_id(remote_worker_id) + .await + }) + }, + ) + .await?; + Ok(worker_id) + } + } +} + pub struct WasmRpcEntryPayload { #[allow(dead_code)] demand: Box, diff --git a/golem-worker-executor-base/src/lib.rs b/golem-worker-executor-base/src/lib.rs index a71754324f..0510cabff8 100644 --- a/golem-worker-executor-base/src/lib.rs +++ b/golem-worker-executor-base/src/lib.rs @@ -307,6 +307,7 @@ pub trait Bootstrap { primary, oplog_archives, golem_config.oplog.entry_count_limit, + golem_config.oplog.max_operations_before_commit_ephemeral, )) } }; diff --git a/golem-worker-executor-base/src/services/golem_config.rs b/golem-worker-executor-base/src/services/golem_config.rs index c4b73c545b..894328f575 100644 --- a/golem-worker-executor-base/src/services/golem_config.rs +++ b/golem-worker-executor-base/src/services/golem_config.rs @@ -240,6 +240,7 @@ pub struct SchedulerConfig { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct OplogConfig { pub max_operations_before_commit: u64, + pub max_operations_before_commit_ephemeral: u64, pub max_payload_size: usize, pub indexed_storage_layers: usize, pub blob_storage_layers: usize, @@ -479,6 +480,7 @@ impl Default for OplogConfig { fn default() -> Self { Self { max_operations_before_commit: 128, + max_operations_before_commit_ephemeral: 512, max_payload_size: 64 * 1024, indexed_storage_layers: 2, blob_storage_layers: 1, diff --git a/golem-worker-executor-base/src/services/oplog/blob.rs b/golem-worker-executor-base/src/services/oplog/blob.rs index 639332e632..c7ae302cf1 100644 --- a/golem-worker-executor-base/src/services/oplog/blob.rs +++ b/golem-worker-executor-base/src/services/oplog/blob.rs @@ -19,10 +19,9 @@ use std::sync::Arc; use async_trait::async_trait; use evicting_cache_map::EvictingCacheMap; -use tokio::sync::RwLock; - use golem_common::model::oplog::{OplogEntry, OplogIndex}; use golem_common::model::{AccountId, ComponentId, OwnedWorkerId, ScanCursor, WorkerId}; +use tokio::sync::RwLock; use crate::error::GolemError; use crate::services::oplog::multilayer::OplogArchive; diff --git a/golem-worker-executor-base/src/services/oplog/ephemeral.rs b/golem-worker-executor-base/src/services/oplog/ephemeral.rs new file mode 100644 index 0000000000..53243d60ac --- /dev/null +++ b/golem-worker-executor-base/src/services/oplog/ephemeral.rs @@ -0,0 +1,178 @@ +// Copyright 2024 Golem Cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::metrics::oplog::record_oplog_call; +use crate::services::oplog::multilayer::OplogArchive; +use crate::services::oplog::{CommitLevel, Oplog}; +use async_mutex::Mutex; +use async_trait::async_trait; +use bytes::Bytes; +use golem_common::model::oplog::{OplogEntry, OplogIndex, OplogPayload}; +use golem_common::model::OwnedWorkerId; +use std::collections::VecDeque; +use std::fmt::{Debug, Formatter}; +use std::sync::Arc; +use std::time::Duration; + +pub struct EphemeralOplog { + owned_worker_id: OwnedWorkerId, + primary: Arc, + target: Arc, + state: Arc>, + close_fn: Option>, +} + +struct EphemeralOplogState { + buffer: VecDeque, + last_oplog_idx: OplogIndex, + last_committed_idx: OplogIndex, + max_operations_before_commit: u64, + target: Arc, +} + +impl EphemeralOplogState { + async fn add(&mut self, entry: OplogEntry) { + self.buffer.push_back(entry); + if self.buffer.len() > self.max_operations_before_commit as usize { + self.commit().await; + } + self.last_oplog_idx = self.last_oplog_idx.next(); + } + + async fn commit(&mut self) { + let entries = self.buffer.drain(..).collect::>(); + + let mut pairs = Vec::new(); + for entry in entries { + let oplog_idx = self.last_committed_idx.next(); + pairs.push((oplog_idx, entry)); + self.last_committed_idx = oplog_idx; + } + + self.target.append(pairs).await + } +} + +impl EphemeralOplog { + pub async fn new( + owned_worker_id: OwnedWorkerId, + last_oplog_idx: OplogIndex, + max_operations_before_commit: u64, + primary: Arc, + target: Arc, + close: Box, + ) -> Self { + Self { + owned_worker_id, + primary, + target: target.clone(), + state: Arc::new(Mutex::new(EphemeralOplogState { + buffer: VecDeque::new(), + last_oplog_idx, + last_committed_idx: last_oplog_idx, + max_operations_before_commit, + target, + })), + close_fn: Some(close), + } + } +} + +impl Drop for EphemeralOplog { + fn drop(&mut self) { + if let Some(close_fn) = self.close_fn.take() { + close_fn(); + } + } +} + +impl Debug for EphemeralOplog { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EphemeralOplog") + .field("worker_id", &self.owned_worker_id) + .finish() + } +} + +#[async_trait] +impl Oplog for EphemeralOplog { + async fn add(&self, entry: OplogEntry) { + record_oplog_call("add"); + let mut state = self.state.lock().await; + state.add(entry).await + } + + async fn drop_prefix(&self, last_dropped_id: OplogIndex) { + record_oplog_call("drop_prefix"); + self.target.drop_prefix(last_dropped_id).await; + } + + async fn commit(&self, level: CommitLevel) { + record_oplog_call("commit"); + match level { + CommitLevel::Immediate => { + let mut state = self.state.lock().await; + state.commit().await + } + CommitLevel::Always => { + let clone = self.state.clone(); + tokio::spawn(async move { + let mut state = clone.lock().await; + state.commit().await + }); + } + CommitLevel::DurableOnly => {} + } + } + + async fn current_oplog_index(&self) -> OplogIndex { + record_oplog_call("current_oplog_index"); + let state = self.state.lock().await; + state.last_oplog_idx + } + + async fn wait_for_replicas(&self, _replicas: u8, _timeout: Duration) -> bool { + record_oplog_call("wait_for_replicas"); + // Not supported + false + } + + async fn read(&self, oplog_index: OplogIndex) -> OplogEntry { + record_oplog_call("read"); + let entries = self.target.read(oplog_index, 1).await; + if let Some(entry) = entries.get(&oplog_index) { + entry.clone() + } else { + panic!( + "Missing oplog entry {oplog_index} in {:?} for ephemeral oplog", + self.target + ); + } + } + + async fn length(&self) -> u64 { + record_oplog_call("length"); + self.target.length().await + } + + async fn upload_payload(&self, data: &[u8]) -> Result { + // Storing oplog payloads through the primary layer + self.primary.upload_payload(data).await + } + + async fn download_payload(&self, payload: &OplogPayload) -> Result { + // Downloading oplog payloads through the primary layer + self.primary.download_payload(payload).await + } +} diff --git a/golem-worker-executor-base/src/services/oplog/mod.rs b/golem-worker-executor-base/src/services/oplog/mod.rs index fa50ca0ab6..47e90bebe6 100644 --- a/golem-worker-executor-base/src/services/oplog/mod.rs +++ b/golem-worker-executor-base/src/services/oplog/mod.rs @@ -31,8 +31,8 @@ use golem_common::model::oplog::{ OplogEntry, OplogIndex, OplogPayload, UpdateDescription, WrappedFunctionType, }; use golem_common::model::{ - AccountId, ComponentId, ComponentVersion, IdempotencyKey, OwnedWorkerId, ScanCursor, Timestamp, - WorkerId, + AccountId, ComponentId, ComponentType, ComponentVersion, IdempotencyKey, OwnedWorkerId, + ScanCursor, Timestamp, WorkerId, }; use golem_common::serialization::{serialize, try_deserialize}; pub use multilayer::{MultiLayerOplog, MultiLayerOplogService, OplogArchiveService}; @@ -42,6 +42,7 @@ use crate::error::GolemError; mod blob; mod compressed; +mod ephemeral; mod multilayer; mod primary; @@ -68,11 +69,13 @@ pub trait OplogService: Debug { &self, owned_worker_id: &OwnedWorkerId, initial_entry: OplogEntry, + component_type: ComponentType, ) -> Arc; async fn open( &self, owned_worker_id: &OwnedWorkerId, last_oplog_index: OplogIndex, + component_type: ComponentType, ) -> Arc; async fn get_last_index(&self, owned_worker_id: &OwnedWorkerId) -> OplogIndex; @@ -132,6 +135,17 @@ pub trait OplogService: Debug { ) -> Result<(ScanCursor, Vec), GolemError>; } +/// Level of commit guarantees +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum CommitLevel { + /// Always commit immediately and do not return until it is done + Immediate, + /// Always commit, both for durable and ephemeral workers, no guarantees that it awaits it + Always, + /// Only commit immediately if the worker is durable + DurableOnly, +} + /// An open oplog providing write access #[async_trait] pub trait Oplog: Any + Debug { @@ -144,7 +158,7 @@ pub trait Oplog: Any + Debug { async fn drop_prefix(&self, last_dropped_id: OplogIndex); /// Commits the buffered entries to the oplog - async fn commit(&self); + async fn commit(&self, level: CommitLevel); /// Returns the current oplog index async fn current_oplog_index(&self) -> OplogIndex; @@ -164,7 +178,7 @@ pub trait Oplog: Any + Debug { /// Adds an entry to the oplog and immediately commits it async fn add_and_commit(&self, entry: OplogEntry) -> OplogIndex { self.add(entry).await; - self.commit().await; + self.commit(CommitLevel::Always).await; self.current_oplog_index().await } diff --git a/golem-worker-executor-base/src/services/oplog/multilayer.rs b/golem-worker-executor-base/src/services/oplog/multilayer.rs index 6b64e1c905..b1a2663b94 100644 --- a/golem-worker-executor-base/src/services/oplog/multilayer.rs +++ b/golem-worker-executor-base/src/services/oplog/multilayer.rs @@ -26,12 +26,15 @@ use tracing::{debug, error, info, warn, Instrument}; use crate::error::GolemError; use golem_common::model::oplog::{OplogEntry, OplogIndex, OplogPayload}; -use golem_common::model::{AccountId, ComponentId, OwnedWorkerId, ScanCursor}; +use golem_common::model::{AccountId, ComponentId, ComponentType, OwnedWorkerId, ScanCursor}; +use crate::services::oplog::ephemeral::EphemeralOplog; use crate::services::oplog::multilayer::BackgroundTransferMessage::{ TransferFromLower, TransferFromPrimary, }; -use crate::services::oplog::{downcast_oplog, OpenOplogs, Oplog, OplogConstructor, OplogService}; +use crate::services::oplog::{ + downcast_oplog, CommitLevel, OpenOplogs, Oplog, OplogConstructor, OplogService, +}; #[async_trait] pub trait OplogArchiveService: Debug { @@ -108,12 +111,13 @@ pub trait OplogArchive: Debug { #[derive(Debug)] pub struct MultiLayerOplogService { - primary: Arc, - lower: NEVec>, + pub primary: Arc, + pub lower: NEVec>, oplogs: OpenOplogs, entry_count_limit: u64, + max_operations_before_commit_ephemeral: u64, } impl MultiLayerOplogService { @@ -121,12 +125,14 @@ impl MultiLayerOplogService { primary: Arc, lower: NEVec>, entry_count_limit: u64, + max_operations_before_commit_ephemeral: u64, ) -> Self { Self { primary, lower, oplogs: OpenOplogs::new("multi-layer oplog"), entry_count_limit, + max_operations_before_commit_ephemeral, } } } @@ -138,6 +144,7 @@ impl Clone for MultiLayerOplogService { lower: self.lower.clone(), oplogs: self.oplogs.clone(), entry_count_limit: self.entry_count_limit, + max_operations_before_commit_ephemeral: self.max_operations_before_commit_ephemeral, } } } @@ -149,6 +156,7 @@ struct CreateOplogConstructor { primary: Arc, service: MultiLayerOplogService, last_oplog_index: OplogIndex, + component_type: ComponentType, } impl CreateOplogConstructor { @@ -158,6 +166,7 @@ impl CreateOplogConstructor { primary: Arc, service: MultiLayerOplogService, last_oplog_index: OplogIndex, + component_type: ComponentType, ) -> Self { Self { owned_worker_id, @@ -165,6 +174,7 @@ impl CreateOplogConstructor { primary, service, last_oplog_index, + component_type, } } } @@ -175,16 +185,57 @@ impl OplogConstructor for CreateOplogConstructor { self, close: Box, ) -> Arc { - let primary = if let Some(initial_entry) = self.initial_entry { - self.primary - .create(&self.owned_worker_id, initial_entry) - .await - } else { - self.primary - .open(&self.owned_worker_id, self.last_oplog_index) - .await - }; - Arc::new(MultiLayerOplog::new(self.owned_worker_id, primary, self.service, close).await) + match self.component_type { + ComponentType::Durable => { + let primary = if let Some(initial_entry) = self.initial_entry { + self.primary + .create(&self.owned_worker_id, initial_entry, self.component_type) + .await + } else { + self.primary + .open( + &self.owned_worker_id, + self.last_oplog_index, + self.component_type, + ) + .await + }; + Arc::new( + MultiLayerOplog::new(self.owned_worker_id, primary, self.service, close).await, + ) + } + ComponentType::Ephemeral => { + let primary = self + .primary + .open( + &self.owned_worker_id, + self.last_oplog_index, + self.component_type, + ) + .await; + + let target_layer = self.service.lower.last(); + let target = target_layer.open(&self.owned_worker_id).await; + + if let Some(initial_entry) = self.initial_entry { + target + .append(vec![(OplogIndex::INITIAL, initial_entry)]) + .await; + } + + Arc::new( + EphemeralOplog::new( + self.owned_worker_id, + self.last_oplog_index, + self.service.max_operations_before_commit_ephemeral, + primary, + target, + close, + ) + .await, + ) + } + } } } @@ -194,6 +245,7 @@ impl OplogService for MultiLayerOplogService { &self, owned_worker_id: &OwnedWorkerId, initial_entry: OplogEntry, + component_type: ComponentType, ) -> Arc { self.oplogs .get_or_open( @@ -204,6 +256,7 @@ impl OplogService for MultiLayerOplogService { self.primary.clone(), self.clone(), OplogIndex::INITIAL, + component_type, ), ) .await @@ -213,6 +266,7 @@ impl OplogService for MultiLayerOplogService { &self, owned_worker_id: &OwnedWorkerId, last_oplog_index: OplogIndex, + component_type: ComponentType, ) -> Arc { debug!("MultiLayerOplogService::open {owned_worker_id}"); self.oplogs @@ -224,6 +278,7 @@ impl OplogService for MultiLayerOplogService { self.primary.clone(), self.clone(), last_oplog_index, + component_type, ), ) .await @@ -570,8 +625,8 @@ impl Oplog for MultiLayerOplog { self.primary_length.set(new_length); } - async fn commit(&self) { - self.primary.commit().await; + async fn commit(&self, level: CommitLevel) { + self.primary.commit(level).await; let count = self.primary_length.get(); if count >= self.multi_layer_oplog_service.entry_count_limit { let current_idx = self.primary.current_oplog_index().await; diff --git a/golem-worker-executor-base/src/services/oplog/primary.rs b/golem-worker-executor-base/src/services/oplog/primary.rs index f84d47bb2a..3f3e11bc38 100644 --- a/golem-worker-executor-base/src/services/oplog/primary.rs +++ b/golem-worker-executor-base/src/services/oplog/primary.rs @@ -14,14 +14,16 @@ use crate::error::GolemError; use crate::metrics::oplog::record_oplog_call; -use crate::services::oplog::{OpenOplogs, Oplog, OplogConstructor, OplogService}; +use crate::services::oplog::{CommitLevel, OpenOplogs, Oplog, OplogConstructor, OplogService}; use crate::storage::blob::{BlobStorage, BlobStorageNamespace}; use crate::storage::indexed::{IndexedStorage, IndexedStorageLabelledApi, IndexedStorageNamespace}; use async_mutex::Mutex; use async_trait::async_trait; use bytes::Bytes; use golem_common::model::oplog::{OplogEntry, OplogIndex, OplogPayload, PayloadId}; -use golem_common::model::{AccountId, ComponentId, OwnedWorkerId, ScanCursor, WorkerId}; +use golem_common::model::{ + AccountId, ComponentId, ComponentType, OwnedWorkerId, ScanCursor, WorkerId, +}; use std::collections::{BTreeMap, VecDeque}; use std::fmt::{Debug, Formatter}; use std::path::Path; @@ -95,6 +97,7 @@ impl OplogService for PrimaryOplogService { &self, owned_worker_id: &OwnedWorkerId, initial_entry: OplogEntry, + component_type: ComponentType, ) -> Arc { record_oplog_call("create"); @@ -122,13 +125,15 @@ impl OplogService for PrimaryOplogService { ) }); - self.open(owned_worker_id, OplogIndex::INITIAL).await + self.open(owned_worker_id, OplogIndex::INITIAL, component_type) + .await } async fn open( &self, owned_worker_id: &OwnedWorkerId, last_oplog_index: OplogIndex, + _component_type: ComponentType, ) -> Arc { record_oplog_call("open"); @@ -374,10 +379,10 @@ struct PrimaryOplogState { } impl PrimaryOplogState { - async fn append(&mut self, arrays: &[OplogEntry]) { + async fn append(&mut self, entries: &[OplogEntry]) { record_oplog_call("append"); - for entry in arrays { + for entry in entries { let oplog_idx = self.last_committed_idx.next(); self.indexed_storage .with_entity("oplog", "append", "entry") @@ -537,7 +542,7 @@ impl Oplog for PrimaryOplog { } } - async fn commit(&self) { + async fn commit(&self, _level: CommitLevel) { let mut state = self.state.lock().await; state.commit().await } diff --git a/golem-worker-executor-base/src/services/oplog/tests.rs b/golem-worker-executor-base/src/services/oplog/tests.rs index da1d515b5a..c6900ddd7d 100644 --- a/golem-worker-executor-base/src/services/oplog/tests.rs +++ b/golem-worker-executor-base/src/services/oplog/tests.rs @@ -237,7 +237,71 @@ async fn open_add_and_read_back() { }; let owned_worker_id = OwnedWorkerId::new(&account_id, &worker_id); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - let oplog = oplog_service.open(&owned_worker_id, last_oplog_index).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await; + + let entry1 = rounded(OplogEntry::jump(OplogRegion { + start: OplogIndex::from_u64(5), + end: OplogIndex::from_u64(12), + })); + let entry2 = rounded(OplogEntry::suspend()); + let entry3 = rounded(OplogEntry::exited()); + + let last_oplog_idx = oplog.current_oplog_index().await; + oplog.add(entry1.clone()).await; + oplog.add(entry2.clone()).await; + oplog.add(entry3.clone()).await; + oplog.commit(CommitLevel::Always).await; + + let r1 = oplog.read(last_oplog_idx.next()).await; + let r2 = oplog.read(last_oplog_idx.next().next()).await; + let r3 = oplog.read(last_oplog_idx.next().next().next()).await; + + assert_eq!(r1, entry1); + assert_eq!(r2, entry2); + assert_eq!(r3, entry3); + + let entries = oplog_service + .read(&owned_worker_id, last_oplog_idx.next(), 3) + .await; + assert_eq!( + entries.into_values().collect::>(), + vec![entry1, entry2, entry3] + ); +} + +#[tokio::test] +async fn open_add_and_read_back_ephemeral() { + let indexed_storage = Arc::new(InMemoryIndexedStorage::new()); + let blob_storage = Arc::new(InMemoryBlobStorage::new()); + let primary_oplog_service = Arc::new( + PrimaryOplogService::new(indexed_storage.clone(), blob_storage.clone(), 1, 100).await, + ); + let secondary_layer: Arc = Arc::new( + CompressedOplogArchiveService::new(indexed_storage.clone(), 1), + ); + let tertiary_layer: Arc = + Arc::new(BlobOplogArchiveService::new(blob_storage.clone(), 2)); + let oplog_service = Arc::new(MultiLayerOplogService::new( + primary_oplog_service.clone(), + nev![secondary_layer.clone(), tertiary_layer.clone()], + 10, + 10, + )); + + let account_id = AccountId { + value: "user1".to_string(), + }; + let worker_id = WorkerId { + component_id: ComponentId(Uuid::new_v4()), + worker_name: "test".to_string(), + }; + let owned_worker_id = OwnedWorkerId::new(&account_id, &worker_id); + let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Ephemeral) + .await; let entry1 = rounded(OplogEntry::jump(OplogRegion { start: OplogIndex::from_u64(5), @@ -250,7 +314,7 @@ async fn open_add_and_read_back() { oplog.add(entry1.clone()).await; oplog.add(entry2.clone()).await; oplog.add(entry3.clone()).await; - oplog.commit().await; + oplog.commit(CommitLevel::Immediate).await; let r1 = oplog.read(last_oplog_idx.next()).await; let r2 = oplog.read(last_oplog_idx.next().next()).await; @@ -284,7 +348,9 @@ async fn entries_with_small_payload() { let owned_worker_id = OwnedWorkerId::new(&account_id, &worker_id); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - let oplog = oplog_service.open(&owned_worker_id, last_oplog_index).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await; let last_oplog_idx = oplog.current_oplog_index().await; let entry1 = rounded( @@ -324,7 +390,7 @@ async fn entries_with_small_payload() { }); oplog.add(entry4.clone()).await; - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; let r1 = oplog.read(last_oplog_idx.next()).await; let r2 = oplog.read(last_oplog_idx.next().next()).await; @@ -390,7 +456,9 @@ async fn entries_with_large_payload() { }; let owned_worker_id = OwnedWorkerId::new(&account_id, &worker_id); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - let oplog = oplog_service.open(&owned_worker_id, last_oplog_index).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await; let large_payload1 = vec![0u8; 1024 * 1024]; let large_payload2 = vec![1u8; 1024 * 1024]; @@ -435,7 +503,7 @@ async fn entries_with_large_payload() { }); oplog.add(entry4.clone()).await; - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; let r1 = oplog.read(last_oplog_idx.next()).await; let r2 = oplog.read(last_oplog_idx.next().next()).await; @@ -558,6 +626,7 @@ async fn multilayer_transfers_entries_after_limit_reached( primary_oplog_service.clone(), nev![secondary_layer.clone(), tertiary_layer.clone()], 10, + 10, )); let account_id = AccountId { @@ -570,7 +639,9 @@ async fn multilayer_transfers_entries_after_limit_reached( let owned_worker_id = OwnedWorkerId::new(&account_id, &worker_id); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - let oplog = oplog_service.open(&owned_worker_id, last_oplog_index).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await; let mut entries = Vec::new(); for i in 0..n { @@ -584,7 +655,7 @@ async fn multilayer_transfers_entries_after_limit_reached( .await .unwrap(), ); - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; entries.push(entry); } @@ -596,6 +667,7 @@ async fn multilayer_transfers_entries_after_limit_reached( .open( &owned_worker_id, primary_oplog_service.get_last_index(&owned_worker_id).await, + ComponentType::Durable, ) .await .length() @@ -654,6 +726,7 @@ async fn read_from_archive_impl(use_blob: bool) { primary_oplog_service.clone(), nev![secondary_layer.clone(), tertiary_layer.clone()], 10, + 10, )); let account_id = AccountId { value: "user1".to_string(), @@ -665,7 +738,9 @@ async fn read_from_archive_impl(use_blob: bool) { let owned_worker_id = OwnedWorkerId::new(&account_id, &worker_id); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - let oplog = oplog_service.open(&owned_worker_id, last_oplog_index).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await; let timestamp = Timestamp::now_utc(); let entries: Vec = (0..100) @@ -682,13 +757,14 @@ async fn read_from_archive_impl(use_blob: bool) { for entry in &entries { oplog.add(entry.clone()).await; } - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; tokio::time::sleep(Duration::from_secs(2)).await; let primary_length = primary_oplog_service .open( &owned_worker_id, primary_oplog_service.get_last_index(&owned_worker_id).await, + ComponentType::Durable, ) .await .length() @@ -771,6 +847,7 @@ async fn write_after_archive_impl(use_blob: bool, reopen: Reopen) { primary_oplog_service.clone(), nev![secondary_layer.clone(), tertiary_layer.clone()], 10, + 10, )); let account_id = AccountId { value: "user1".to_string(), @@ -783,7 +860,9 @@ async fn write_after_archive_impl(use_blob: bool, reopen: Reopen) { info!("FIRST OPEN"); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - let oplog = oplog_service.open(&owned_worker_id, last_oplog_index).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await; info!("FIRST OPEN DONE"); let timestamp = Timestamp::now_utc(); @@ -801,13 +880,14 @@ async fn write_after_archive_impl(use_blob: bool, reopen: Reopen) { for entry in &entries { oplog.add(entry.clone()).await; } - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; tokio::time::sleep(Duration::from_secs(2)).await; let primary_length = primary_oplog_service .open( &owned_worker_id, primary_oplog_service.get_last_index(&owned_worker_id).await, + ComponentType::Durable, ) .await .length() @@ -823,7 +903,9 @@ async fn write_after_archive_impl(use_blob: bool, reopen: Reopen) { let oplog = if reopen == Reopen::Yes { drop(oplog); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - oplog_service.open(&owned_worker_id, last_oplog_index).await + oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await } else if reopen == Reopen::Full { drop(oplog); primary_oplog_service = Arc::new( @@ -833,9 +915,12 @@ async fn write_after_archive_impl(use_blob: bool, reopen: Reopen) { primary_oplog_service.clone(), nev![secondary_layer.clone(), tertiary_layer.clone()], 10, + 10, )); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - oplog_service.open(&owned_worker_id, last_oplog_index).await + oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await } else { oplog }; @@ -852,16 +937,17 @@ async fn write_after_archive_impl(use_blob: bool, reopen: Reopen) { for (n, entry) in entries.iter().enumerate() { oplog.add(entry.clone()).await; if n % 100 == 0 { - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; } } - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; tokio::time::sleep(Duration::from_secs(2)).await; let primary_length = primary_oplog_service .open( &owned_worker_id, primary_oplog_service.get_last_index(&owned_worker_id).await, + ComponentType::Durable, ) .await .length() @@ -877,7 +963,9 @@ async fn write_after_archive_impl(use_blob: bool, reopen: Reopen) { let oplog = if reopen == Reopen::Yes { drop(oplog); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - oplog_service.open(&owned_worker_id, last_oplog_index).await + oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await } else if reopen == Reopen::Full { drop(oplog); primary_oplog_service = Arc::new( @@ -887,9 +975,12 @@ async fn write_after_archive_impl(use_blob: bool, reopen: Reopen) { primary_oplog_service.clone(), nev![secondary_layer.clone(), tertiary_layer.clone()], 10, + 10, )); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - oplog_service.open(&owned_worker_id, last_oplog_index).await + oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await } else { oplog }; @@ -900,7 +991,7 @@ async fn write_after_archive_impl(use_blob: bool, reopen: Reopen) { error: WorkerError::Unknown("last".to_string()), })) .await; - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; drop(oplog); let entry1 = oplog_service @@ -987,6 +1078,7 @@ async fn empty_layer_gets_deleted_impl(use_blob: bool) { primary_oplog_service.clone(), nev![secondary_layer.clone(), tertiary_layer.clone()], 10, + 10, )); let account_id = AccountId { value: "user1".to_string(), @@ -998,7 +1090,9 @@ async fn empty_layer_gets_deleted_impl(use_blob: bool) { let owned_worker_id = OwnedWorkerId::new(&account_id, &worker_id); let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - let oplog = oplog_service.open(&owned_worker_id, last_oplog_index).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await; // As we add 100 entries at once, and that exceeds the limit, we expect that all entries have // been moved to the secondary layer. By doing this 10 more times, we end up having all entries @@ -1018,7 +1112,7 @@ async fn empty_layer_gets_deleted_impl(use_blob: bool) { for entry in &entries { oplog.add(entry.clone()).await; } - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; tokio::time::sleep(Duration::from_millis(100)).await; } @@ -1032,6 +1126,7 @@ async fn empty_layer_gets_deleted_impl(use_blob: bool) { .open( &owned_worker_id, primary_oplog_service.get_last_index(&owned_worker_id).await, + ComponentType::Durable, ) .await .length() @@ -1088,6 +1183,7 @@ async fn scheduled_archive_impl(use_blob: bool) { primary_oplog_service.clone(), nev![secondary_layer.clone(), tertiary_layer.clone()], 1000, // no transfer will occur by reaching limit in this test + 10, )); let account_id = AccountId { value: "user1".to_string(), @@ -1111,11 +1207,13 @@ async fn scheduled_archive_impl(use_blob: bool) { // Adding 100 entries to the primary oplog, schedule archive and immediately drop the oplog let archive_result = { let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - let oplog = oplog_service.open(&owned_worker_id, last_oplog_index).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await; for entry in &entries { oplog.add(entry.clone()).await; } - oplog.commit().await; + oplog.commit(CommitLevel::Always).await; let result = MultiLayerOplog::try_archive(&oplog).await; drop(oplog); @@ -1130,6 +1228,7 @@ async fn scheduled_archive_impl(use_blob: bool) { .open( &owned_worker_id, primary_oplog_service.get_last_index(&owned_worker_id).await, + ComponentType::Durable, ) .await .length() @@ -1153,7 +1252,9 @@ async fn scheduled_archive_impl(use_blob: bool) { // Calling archive again let archive_result2 = { let last_oplog_index = oplog_service.get_last_index(&owned_worker_id).await; - let oplog = oplog_service.open(&owned_worker_id, last_oplog_index).await; + let oplog = oplog_service + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) + .await; let result = MultiLayerOplog::try_archive(&oplog).await; drop(oplog); result @@ -1165,6 +1266,7 @@ async fn scheduled_archive_impl(use_blob: bool) { .open( &owned_worker_id, primary_oplog_service.get_last_index(&owned_worker_id).await, + ComponentType::Durable, ) .await .length() diff --git a/golem-worker-executor-base/src/services/rpc.rs b/golem-worker-executor-base/src/services/rpc.rs index 1586a69a63..0fceabfc88 100644 --- a/golem-worker-executor-base/src/services/rpc.rs +++ b/golem-worker-executor-base/src/services/rpc.rs @@ -22,10 +22,11 @@ use golem_wasm_rpc::WitValue; use tokio::runtime::Handle; use tracing::debug; -use golem_common::model::{IdempotencyKey, OwnedWorkerId, WorkerId}; +use golem_common::model::{IdempotencyKey, OwnedWorkerId, TargetWorkerId, WorkerId}; use crate::error::GolemError; use crate::services::events::Events; +use crate::services::shard::ShardService; use crate::services::worker_proxy::{WorkerProxy, WorkerProxyError}; use crate::services::{ active_workers, blob_store, component, golem_config, key_value, oplog, promise, scheduler, @@ -64,6 +65,11 @@ pub trait Rpc { self_args: &[String], self_env: &[(String, String)], ) -> Result<(), RpcError>; + + async fn generate_unique_local_worker_id( + &self, + target_worker_id: TargetWorkerId, + ) -> Result; } #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] @@ -143,11 +149,18 @@ pub trait RpcDemand: Send + Sync {} pub struct RemoteInvocationRpc { worker_proxy: Arc, + shard_service: Arc, } impl RemoteInvocationRpc { - pub fn new(worker_proxy: Arc) -> Self { - Self { worker_proxy } + pub fn new( + worker_proxy: Arc, + shard_service: Arc, + ) -> Self { + Self { + worker_proxy, + shard_service, + } } } @@ -225,6 +238,17 @@ impl Rpc for RemoteInvocationRpc { ) .await?) } + + async fn generate_unique_local_worker_id( + &self, + target_worker_id: TargetWorkerId, + ) -> Result { + let current_assignment = self.shard_service.current_assignment()?; + Ok(target_worker_id.into_worker_id( + ¤t_assignment.shard_ids, + current_assignment.number_of_shards, + )) + } } pub struct DirectWorkerInvocationRpc { @@ -529,7 +553,7 @@ impl Rpc for DirectWorkerInvocationRpc { self_args: &[String], self_env: &[(String, String)], ) -> Result<(), RpcError> { - let idempotency_key = idempotency_key.unwrap_or(IdempotencyKey::fresh()); + let idempotency_key = idempotency_key.unwrap_or(IdempotencyKey::fresh()); // TODO if self .shard_service() @@ -571,6 +595,15 @@ impl Rpc for DirectWorkerInvocationRpc { .await } } + + async fn generate_unique_local_worker_id( + &self, + target_worker_id: TargetWorkerId, + ) -> Result { + self.remote_rpc + .generate_unique_local_worker_id(target_worker_id) + .await + } } impl RpcDemand for () {} diff --git a/golem-worker-executor-base/src/services/scheduler.rs b/golem-worker-executor-base/src/services/scheduler.rs index 8c884f815d..fcd16701a4 100644 --- a/golem-worker-executor-base/src/services/scheduler.rs +++ b/golem-worker-executor-base/src/services/scheduler.rs @@ -22,7 +22,7 @@ use chrono::{DateTime, TimeZone, Utc}; use tokio::task::JoinHandle; use tracing::{error, span, warn, Instrument, Level}; -use golem_common::model::{ScheduleId, ScheduledAction}; +use golem_common::model::{ComponentType, ScheduleId, ScheduledAction}; use crate::metrics::promises::record_scheduled_promise_completed; use crate::services::oplog::{MultiLayerOplog, OplogService}; @@ -159,9 +159,11 @@ impl SchedulerServiceDefault { let current_last_index = self.oplog_service.get_last_index(&owned_worker_id).await; if current_last_index == last_oplog_index { + // We never schedule an archive operation for ephemeral workers, because they immediately write their oplog to the arcchive layer + // So we can assume the component type is Durable here without calculating it from the latest component and worker metadata. let oplog = self .oplog_service - .open(&owned_worker_id, last_oplog_index) + .open(&owned_worker_id, last_oplog_index, ComponentType::Durable) .await; if let Some(more) = MultiLayerOplog::try_archive(&oplog).await { if more { diff --git a/golem-worker-executor-base/src/services/worker.rs b/golem-worker-executor-base/src/services/worker.rs index af647e3592..f3c61d2fac 100644 --- a/golem-worker-executor-base/src/services/worker.rs +++ b/golem-worker-executor-base/src/services/worker.rs @@ -129,7 +129,7 @@ impl WorkerService for DefaultWorkerService { worker_metadata.last_known_status.total_linear_memory_size, ); self.oplog_service - .create(&owned_worker_id, initial_oplog_entry) + .create(&owned_worker_id, initial_oplog_entry, component_type) .await; if component_type != ComponentType::Ephemeral { diff --git a/golem-worker-executor-base/src/worker.rs b/golem-worker-executor-base/src/worker.rs index 10cf4faa31..941a0b8c07 100644 --- a/golem-worker-executor-base/src/worker.rs +++ b/golem-worker-executor-base/src/worker.rs @@ -26,7 +26,7 @@ use crate::invocation::{invoke_worker, InvokeResult}; use crate::model::{ExecutionStatus, InterruptKind, LookupResult, TrapType, WorkerConfig}; use crate::services::component::ComponentMetadata; use crate::services::events::Event; -use crate::services::oplog::{Oplog, OplogOps}; +use crate::services::oplog::{CommitLevel, Oplog, OplogOps}; use crate::services::worker_event::{WorkerEventService, WorkerEventServiceDefault}; use crate::services::{ All, HasActiveWorkers, HasAll, HasBlobStoreService, HasComponentService, HasConfig, HasEvents, @@ -173,10 +173,21 @@ impl Worker { parent, ) .await?; + let initial_component_metadata = deps + .component_service() + .get_metadata( + &owned_worker_id.worker_id.component_id, + Some(worker_metadata.last_known_status.component_version), + ) + .await?; let last_oplog_index = deps.oplog_service().get_last_index(&owned_worker_id).await; let oplog = deps .oplog_service() - .open(&owned_worker_id, last_oplog_index) + .open( + &owned_worker_id, + last_oplog_index, + initial_component_metadata.component_type, + ) .await; let initial_pending_invocations = worker_metadata @@ -191,13 +202,6 @@ impl Worker { .collect::>(); let initial_invocation_results = worker_metadata.last_known_status.invocation_results.clone(); - let initial_component_metadata = deps - .component_service() - .get_metadata( - &owned_worker_id.worker_id.component_id, - Some(worker_metadata.last_known_status.component_version), - ) - .await?; let queue = Arc::new(RwLock::new(VecDeque::from_iter( initial_pending_invocations.iter().cloned(), @@ -647,7 +651,7 @@ impl Worker { pub async fn update_status(&self, status_value: WorkerStatusRecord) { // Need to make sure the oplog is committed, because the updated status stores the current // last oplog index as reference. - self.oplog().commit().await; + self.oplog().commit(CommitLevel::DurableOnly).await; // Storing the status in the key-value storage let component_type = self.execution_status.read().unwrap().component_type(); self.worker_service() @@ -1663,6 +1667,16 @@ impl RunningWorker { } } + // Make sure all pending commits are done + store + .lock() + .await + .data_mut() + .get_public_state() + .oplog() + .commit(CommitLevel::Immediate) + .await; + match final_decision { RetryDecision::Immediate => { debug!("Invocation queue loop triggering restart immediately"); diff --git a/golem-worker-executor-base/tests/api.rs b/golem-worker-executor-base/tests/api.rs index fd1052b2c1..3a6f82ebd2 100644 --- a/golem-worker-executor-base/tests/api.rs +++ b/golem-worker-executor-base/tests/api.rs @@ -1179,7 +1179,7 @@ async fn get_worker_metadata() { value: "test-account".to_string() } ); - check!(metadata2.last_known_status.component_size == 60756); + check!(metadata2.last_known_status.component_size == 60157); check!(metadata2.last_known_status.total_linear_memory_size == 1245184); } diff --git a/golem-worker-executor-base/tests/common/mod.rs b/golem-worker-executor-base/tests/common/mod.rs index 6792e2bb25..3215ae0db1 100644 --- a/golem-worker-executor-base/tests/common/mod.rs +++ b/golem-worker-executor-base/tests/common/mod.rs @@ -769,7 +769,10 @@ impl Bootstrap for ServerBootstrap { events: Arc, ) -> anyhow::Result> { let rpc = Arc::new(DirectWorkerInvocationRpc::new( - Arc::new(RemoteInvocationRpc::new(worker_proxy.clone())), + Arc::new(RemoteInvocationRpc::new( + worker_proxy.clone(), + shard_service.clone(), + )), active_workers.clone(), engine.clone(), linker.clone(), diff --git a/golem-worker-executor-base/tests/rust_rpc.rs b/golem-worker-executor-base/tests/rust_rpc.rs index 996a1f3061..702b631c01 100644 --- a/golem-worker-executor-base/tests/rust_rpc.rs +++ b/golem-worker-executor-base/tests/rust_rpc.rs @@ -13,12 +13,13 @@ // limitations under the License. use crate::common; +use crate::common::{start, TestContext}; use assert2::check; use golem_test_framework::dsl::{worker_error_message, TestDslUnsafe}; use golem_wasm_rpc::Value; use std::collections::HashMap; use std::time::SystemTime; -use tracing::debug; +use tracing::{debug, info}; #[tokio::test] #[tracing::instrument] @@ -625,3 +626,67 @@ async fn error_message_non_existing_target_component() { check!(worker_error_message(&create_auction_result.err().unwrap()) .contains("Could not find any component with the given id")); } + +#[tokio::test] +#[tracing::instrument] +async fn ephemeral_worker_invocation_via_rpc1() { + let context = TestContext::new(); + let executor = start(&context).await.unwrap(); + + let ephemeral_component_id = executor.store_ephemeral_component("ephemeral").await; + let caller_component_id = executor.store_component("caller_composed").await; + + let mut env = HashMap::new(); + env.insert( + "EPHEMERAL_COMPONENT_ID".to_string(), + ephemeral_component_id.to_string(), + ); + let caller_worker_id = executor + .start_worker_with(&caller_component_id, "rpc-ephemeral-1", vec![], env) + .await; + + let result = executor + .invoke_and_await(&caller_worker_id, "ephemeral-test1", vec![]) + .await + .unwrap(); + + drop(executor); + + info!("result is: {result:?}"); + + match result.into_iter().next() { + Some(Value::List(items)) => { + let pairs = items + .into_iter() + .filter_map(|item| match item { + Value::Tuple(values) if values.len() == 2 => { + let mut iter = values.into_iter(); + let key = iter.next(); + let value = iter.next(); + match (key, value) { + (Some(Value::String(key)), Some(Value::String(value))) => { + Some((key, value)) + } + _ => None, + } + } + _ => None, + }) + .collect::>(); + + check!(pairs.len() == 3); + let name1 = &pairs[0].0; + let value1 = &pairs[0].1; + let name2 = &pairs[1].0; + let value2 = &pairs[1].1; + let name3 = &pairs[2].0; + let value3 = &pairs[2].1; + + check!(name1 == name2); + check!(name2 != name3); + check!(value1 != value2); + check!(value2 != value3); + } + _ => panic!("Unexpected result value"), + } +} diff --git a/golem-worker-executor-base/tests/transactions.rs b/golem-worker-executor-base/tests/transactions.rs index cf02519a83..f73ca2b316 100644 --- a/golem-worker-executor-base/tests/transactions.rs +++ b/golem-worker-executor-base/tests/transactions.rs @@ -15,6 +15,7 @@ use crate::common::{start, TestContext}; use assert2::check; use bytes::Bytes; +use golem_common::model::{IdempotencyKey, TargetWorkerId}; use golem_test_framework::dsl::{ drain_connection, stdout_event_starting_with, stdout_events, worker_error_message, TestDslUnsafe, @@ -720,3 +721,104 @@ async fn golem_rust_infallible_transaction() { ] ); } + +#[tokio::test] +#[tracing::instrument] +async fn idempotency_keys_in_ephemeral_workers() { + let context = TestContext::new(); + let executor = start(&context).await.unwrap(); + + let component_id = executor.store_ephemeral_component("runtime-service").await; + + let target_worker_id = TargetWorkerId { + component_id, + worker_name: None, + }; + + let idempotency_key1 = IdempotencyKey::fresh(); + let idempotency_key2 = IdempotencyKey::fresh(); + + let result11 = executor + .invoke_and_await( + target_worker_id.clone(), + "golem:it/api.{generate-idempotency-keys}", + vec![], + ) + .await + .unwrap(); + let result21 = executor + .invoke_and_await_with_key( + target_worker_id.clone(), + &idempotency_key1, + "golem:it/api.{generate-idempotency-keys}", + vec![], + ) + .await + .unwrap(); + let result31 = executor + .invoke_and_await_with_key( + target_worker_id.clone(), + &idempotency_key2, + "golem:it/api.{generate-idempotency-keys}", + vec![], + ) + .await + .unwrap(); + let result12 = executor + .invoke_and_await( + target_worker_id.clone(), + "golem:it/api.{generate-idempotency-keys}", + vec![], + ) + .await + .unwrap(); + let result22 = executor + .invoke_and_await_with_key( + target_worker_id.clone(), + &idempotency_key1, + "golem:it/api.{generate-idempotency-keys}", + vec![], + ) + .await + .unwrap(); + let result32 = executor + .invoke_and_await_with_key( + target_worker_id.clone(), + &idempotency_key2, + "golem:it/api.{generate-idempotency-keys}", + vec![], + ) + .await + .unwrap(); + + drop(executor); + + fn returned_keys_are_different(value: &[Value]) -> bool { + if value.len() == 1 { + if let Value::Tuple(items) = &value[0] { + if items.len() == 2 { + items[0] != items[1] + } else { + false + } + } else { + false + } + } else { + false + } + } + + check!(returned_keys_are_different(&result11)); + check!(returned_keys_are_different(&result21)); + check!(returned_keys_are_different(&result31)); + check!(returned_keys_are_different(&result12)); + check!(returned_keys_are_different(&result22)); + check!(returned_keys_are_different(&result32)); + + check!(result11 != result12); // when not providing idempotency key it should return different keys + check!(result11 != result21); + check!(result11 != result31); + check!(result21 == result22); // same idempotency key should lead to the same result + check!(result31 == result32); +} diff --git a/golem-worker-executor/config/worker-executor.sample.env b/golem-worker-executor/config/worker-executor.sample.env index 4652043560..c91882930b 100644 --- a/golem-worker-executor/config/worker-executor.sample.env +++ b/golem-worker-executor/config/worker-executor.sample.env @@ -60,6 +60,7 @@ GOLEM__OPLOG__BLOB_STORAGE_LAYERS=1 GOLEM__OPLOG__ENTRY_COUNT_LIMIT=1024 GOLEM__OPLOG__INDEXED_STORAGE_LAYERS=2 GOLEM__OPLOG__MAX_OPERATIONS_BEFORE_COMMIT=128 +GOLEM__OPLOG__MAX_OPERATIONS_BEFORE_COMMIT_EPHEMERAL=512 GOLEM__OPLOG__MAX_PAYLOAD_SIZE=65536 GOLEM__PUBLIC_WORKER_API__ACCESS_TOKEN="2a354594-7a63-4091-a46b-cc58d379f677" GOLEM__PUBLIC_WORKER_API__HOST="localhost" @@ -179,6 +180,7 @@ GOLEM__OPLOG__BLOB_STORAGE_LAYERS=1 GOLEM__OPLOG__ENTRY_COUNT_LIMIT=1024 GOLEM__OPLOG__INDEXED_STORAGE_LAYERS=2 GOLEM__OPLOG__MAX_OPERATIONS_BEFORE_COMMIT=128 +GOLEM__OPLOG__MAX_OPERATIONS_BEFORE_COMMIT_EPHEMERAL=512 GOLEM__OPLOG__MAX_PAYLOAD_SIZE=65536 GOLEM__PUBLIC_WORKER_API__ACCESS_TOKEN="2a354594-7a63-4091-a46b-cc58d379f677" GOLEM__PUBLIC_WORKER_API__HOST="localhost" @@ -265,6 +267,7 @@ GOLEM__OPLOG__BLOB_STORAGE_LAYERS=1 GOLEM__OPLOG__ENTRY_COUNT_LIMIT=1024 GOLEM__OPLOG__INDEXED_STORAGE_LAYERS=2 GOLEM__OPLOG__MAX_OPERATIONS_BEFORE_COMMIT=128 +GOLEM__OPLOG__MAX_OPERATIONS_BEFORE_COMMIT_EPHEMERAL=512 GOLEM__OPLOG__MAX_PAYLOAD_SIZE=65536 GOLEM__PUBLIC_WORKER_API__ACCESS_TOKEN="2a354594-7a63-4091-a46b-cc58d379f677" GOLEM__PUBLIC_WORKER_API__HOST="localhost" diff --git a/golem-worker-executor/config/worker-executor.toml b/golem-worker-executor/config/worker-executor.toml index 842acbd693..d85c0a0bea 100644 --- a/golem-worker-executor/config/worker-executor.toml +++ b/golem-worker-executor/config/worker-executor.toml @@ -89,6 +89,7 @@ blob_storage_layers = 1 entry_count_limit = 1024 indexed_storage_layers = 2 max_operations_before_commit = 128 +max_operations_before_commit_ephemeral = 512 max_payload_size = 65536 [public_worker_api] @@ -258,6 +259,7 @@ without_time = false # entry_count_limit = 1024 # indexed_storage_layers = 2 # max_operations_before_commit = 128 +# max_operations_before_commit_ephemeral = 512 # max_payload_size = 65536 # # [public_worker_api] @@ -384,6 +386,7 @@ without_time = false # entry_count_limit = 1024 # indexed_storage_layers = 2 # max_operations_before_commit = 128 +# max_operations_before_commit_ephemeral = 512 # max_payload_size = 65536 # # [public_worker_api] diff --git a/golem-worker-executor/src/lib.rs b/golem-worker-executor/src/lib.rs index f8ef1db913..9ac1e0892c 100644 --- a/golem-worker-executor/src/lib.rs +++ b/golem-worker-executor/src/lib.rs @@ -83,7 +83,10 @@ impl Bootstrap for ServerBootstrap { let additional_deps = AdditionalDeps {}; let rpc = Arc::new(DirectWorkerInvocationRpc::new( - Arc::new(RemoteInvocationRpc::new(worker_proxy.clone())), + Arc::new(RemoteInvocationRpc::new( + worker_proxy.clone(), + shard_service.clone(), + )), active_workers.clone(), engine.clone(), linker.clone(), diff --git a/golem-worker-service-base/src/api_definition/http/http_api_definition.rs b/golem-worker-service-base/src/api_definition/http/http_api_definition.rs index 753169b289..50cd8a067b 100644 --- a/golem-worker-service-base/src/api_definition/http/http_api_definition.rs +++ b/golem-worker-service-base/src/api_definition/http/http_api_definition.rs @@ -80,13 +80,11 @@ impl From for HttpApiDefinition { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Clone, PartialEq)] pub struct CompiledHttpApiDefinition { pub id: ApiDefinitionId, pub version: ApiVersion, pub routes: Vec, - #[serde(default)] pub draft: bool, pub created_at: chrono::DateTime, } @@ -350,7 +348,7 @@ pub struct Route { pub binding: GolemWorkerBinding, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Encode, Decode)] pub struct CompiledRoute { pub method: MethodPattern, pub path: AllPathPatterns, diff --git a/golem-worker-service-base/src/worker_binding/compiled_golem_worker_binding.rs b/golem-worker-service-base/src/worker_binding/compiled_golem_worker_binding.rs index c524d10740..ea45a8e8d1 100644 --- a/golem-worker-service-base/src/worker_binding/compiled_golem_worker_binding.rs +++ b/golem-worker-service-base/src/worker_binding/compiled_golem_worker_binding.rs @@ -3,9 +3,8 @@ use bincode::{Decode, Encode}; use golem_service_base::model::VersionedComponentId; use golem_wasm_ast::analysis::AnalysedExport; use rib::{Expr, RibByteCode, RibInputTypeInfo}; -use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Encode, Decode)] pub struct CompiledGolemWorkerBinding { pub component_id: VersionedComponentId, pub worker_name_compiled: WorkerNameCompiled, @@ -43,7 +42,7 @@ impl CompiledGolemWorkerBinding { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Encode, Decode)] pub struct WorkerNameCompiled { pub worker_name: Expr, pub compiled_worker_name: RibByteCode, @@ -65,7 +64,7 @@ impl WorkerNameCompiled { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Encode, Decode)] pub struct IdempotencyKeyCompiled { pub idempotency_key: Expr, pub compiled_idempotency_key: RibByteCode, @@ -87,7 +86,7 @@ impl IdempotencyKeyCompiled { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Encode, Decode)] pub struct ResponseMappingCompiled { pub response_rib_expr: Expr, pub compiled_response: RibByteCode, diff --git a/golem-worker-service-base/src/worker_bridge_execution/mod.rs b/golem-worker-service-base/src/worker_bridge_execution/mod.rs index 5d5d8c4496..3e35427c53 100644 --- a/golem-worker-service-base/src/worker_bridge_execution/mod.rs +++ b/golem-worker-service-base/src/worker_bridge_execution/mod.rs @@ -4,14 +4,13 @@ use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; mod content_type_mapper; pub mod to_response; mod worker_request_executor; -use rib::ParsedFunctionName; pub use worker_request_executor::*; #[derive(PartialEq, Debug, Clone)] pub struct WorkerRequest { pub component_id: ComponentId, pub worker_name: String, - pub function_name: ParsedFunctionName, + pub function_name: String, pub function_params: Vec, pub idempotency_key: Option, } diff --git a/golem-worker-service-base/src/worker_service_rib_interpreter/mod.rs b/golem-worker-service-base/src/worker_service_rib_interpreter/mod.rs index ae71b6d666..e19d8d9b66 100644 --- a/golem-worker-service-base/src/worker_service_rib_interpreter/mod.rs +++ b/golem-worker-service-base/src/worker_service_rib_interpreter/mod.rs @@ -8,7 +8,7 @@ use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use golem_common::model::{ComponentId, IdempotencyKey}; use crate::worker_binding::RibInputValue; -use rib::{ParsedFunctionName, RibByteCode, RibFunctionInvoke, RibInterpreterResult}; +use rib::{RibByteCode, RibFunctionInvoke, RibInterpreterResult}; use crate::worker_bridge_execution::{ NoopWorkerRequestExecutor, WorkerRequest, WorkerRequestExecutor, @@ -86,7 +86,7 @@ impl WorkerServiceRibInterpreter for DefaultEvaluator { let idempotency_key = idempotency_key.clone(); let worker_invoke_function: RibFunctionInvoke = Arc::new( - move |function_name: ParsedFunctionName, parameters: Vec| { + move |function_name: String, parameters: Vec| { let worker_name = worker_name.to_string(); let component_id = component_id.clone(); let worker_name = worker_name.clone(); diff --git a/golem-worker-service/src/worker_bridge_request_executor.rs b/golem-worker-service/src/worker_bridge_request_executor.rs index 0ed9af9b8f..fb44ae78ca 100644 --- a/golem-worker-service/src/worker_bridge_request_executor.rs +++ b/golem-worker-service/src/worker_bridge_request_executor.rs @@ -92,7 +92,7 @@ mod internal { .invoke_and_await_function_json( &worker_id.into_target_worker_id(), worker_request_params.idempotency_key, - worker_request_params.function_name.to_string(), + worker_request_params.function_name, invoke_parameters, None, empty_worker_metadata(), diff --git a/test-components/blob-store-service.wasm b/test-components/blob-store-service.wasm index 3d72580153..c6fd451b60 100755 Binary files a/test-components/blob-store-service.wasm and b/test-components/blob-store-service.wasm differ diff --git a/test-components/caller_composed.wasm b/test-components/caller_composed.wasm index 92069a7806..ed5f61f9f1 100644 Binary files a/test-components/caller_composed.wasm and b/test-components/caller_composed.wasm differ diff --git a/test-components/clock-service.wasm b/test-components/clock-service.wasm index 48ba61f9a5..15d272b00b 100755 Binary files a/test-components/clock-service.wasm and b/test-components/clock-service.wasm differ diff --git a/test-components/clocks.wasm b/test-components/clocks.wasm index ca06211571..c6d7ffbf13 100755 Binary files a/test-components/clocks.wasm and b/test-components/clocks.wasm differ diff --git a/test-components/counters.wasm b/test-components/counters.wasm index 53edced62d..d58151ac5c 100755 Binary files a/test-components/counters.wasm and b/test-components/counters.wasm differ diff --git a/test-components/directories.wasm b/test-components/directories.wasm index d54349917a..c1ddb5eb5e 100755 Binary files a/test-components/directories.wasm and b/test-components/directories.wasm differ diff --git a/test-components/durability-overhead.wasm b/test-components/durability-overhead.wasm index 56a9de3f8a..fc86fb6be3 100644 Binary files a/test-components/durability-overhead.wasm and b/test-components/durability-overhead.wasm differ diff --git a/test-components/environment-service.wasm b/test-components/environment-service.wasm index 24588cff3f..da84896dee 100755 Binary files a/test-components/environment-service.wasm and b/test-components/environment-service.wasm differ diff --git a/test-components/ephemeral.wasm b/test-components/ephemeral.wasm new file mode 100644 index 0000000000..469169168e Binary files /dev/null and b/test-components/ephemeral.wasm differ diff --git a/test-components/failing-component.wasm b/test-components/failing-component.wasm index 5ecef7bc2d..2feebeabfd 100755 Binary files a/test-components/failing-component.wasm and b/test-components/failing-component.wasm differ diff --git a/test-components/file-service.wasm b/test-components/file-service.wasm index 7e43cb0ebb..a49b6e0659 100755 Binary files a/test-components/file-service.wasm and b/test-components/file-service.wasm differ diff --git a/test-components/file-write-read-delete.wasm b/test-components/file-write-read-delete.wasm index d69758cbde..c6a0bea499 100755 Binary files a/test-components/file-write-read-delete.wasm and b/test-components/file-write-read-delete.wasm differ diff --git a/test-components/flags-service.wasm b/test-components/flags-service.wasm index c2986bb24f..5b29adb2bf 100755 Binary files a/test-components/flags-service.wasm and b/test-components/flags-service.wasm differ diff --git a/test-components/golem-rust-tests.wasm b/test-components/golem-rust-tests.wasm index b11629e96b..51698131d4 100755 Binary files a/test-components/golem-rust-tests.wasm and b/test-components/golem-rust-tests.wasm differ diff --git a/test-components/http-client-2.wasm b/test-components/http-client-2.wasm index 9199e3687a..162af613ae 100755 Binary files a/test-components/http-client-2.wasm and b/test-components/http-client-2.wasm differ diff --git a/test-components/http-client.wasm b/test-components/http-client.wasm index 013dbba51f..3356051768 100755 Binary files a/test-components/http-client.wasm and b/test-components/http-client.wasm differ diff --git a/test-components/interruption.wasm b/test-components/interruption.wasm index a5b63a13b9..06a6441fc8 100755 Binary files a/test-components/interruption.wasm and b/test-components/interruption.wasm differ diff --git a/test-components/key-value-service.wasm b/test-components/key-value-service.wasm index 5a88062052..ca6666801f 100755 Binary files a/test-components/key-value-service.wasm and b/test-components/key-value-service.wasm differ diff --git a/test-components/networking.wasm b/test-components/networking.wasm index 0a8512a02f..2f7658e0c6 100755 Binary files a/test-components/networking.wasm and b/test-components/networking.wasm differ diff --git a/test-components/option-service.wasm b/test-components/option-service.wasm index bd59c0a345..5c5aa1d8db 100755 Binary files a/test-components/option-service.wasm and b/test-components/option-service.wasm differ diff --git a/test-components/read-stdin.wasm b/test-components/read-stdin.wasm index d71e485579..52a2d2ade9 100755 Binary files a/test-components/read-stdin.wasm and b/test-components/read-stdin.wasm differ diff --git a/test-components/rpc/Cargo.lock b/test-components/rpc/Cargo.lock index 1cf0b9f36c..d862db634e 100644 --- a/test-components/rpc/Cargo.lock +++ b/test-components/rpc/Cargo.lock @@ -39,6 +39,38 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -69,6 +101,25 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +[[package]] +name = "ephemeral" +version = "0.0.1" +dependencies = [ + "golem-rust", + "once_cell", + "rand", + "uuid", + "wit-bindgen-rt", +] + +[[package]] +name = "ephemeral-stub" +version = "0.0.1" +dependencies = [ + "golem-wasm-rpc", + "wit-bindgen-rt", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -108,10 +159,36 @@ dependencies = [ "wasi", ] +[[package]] +name = "golem-rust" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ef0670496530779ccc42076031e1ebce93aee07129b1c410e31bee577be85c" +dependencies = [ + "golem-rust-macro", + "serde", + "serde_json", + "uuid", + "wit-bindgen-rt", +] + +[[package]] +name = "golem-rust-macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eb977d485e1d5d0d2fc7db022689b740615639867f932702f7d176f786a8e0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "golem-wasm-rpc" version = "0.0.0" dependencies = [ + "cargo_metadata", "prost-build", "wit-bindgen-rt", ] @@ -147,6 +224,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "libc" version = "0.2.155" @@ -352,26 +435,53 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + [[package]] name = "serde" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "syn" version = "2.0.67" @@ -395,6 +505,26 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -403,9 +533,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "uuid" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", "serde", diff --git a/test-components/rpc/Cargo.toml b/test-components/rpc/Cargo.toml index ef0d38bb84..45846c2e99 100644 --- a/test-components/rpc/Cargo.toml +++ b/test-components/rpc/Cargo.toml @@ -1,11 +1,7 @@ [workspace] resolver = "2" -members = [ - "counters", - "caller", - "counters-stub" -] +members = ["counters", "caller", "ephemeral", "ephemeral-stub", "counters-stub"] [profile.release] opt-level = "s" diff --git a/test-components/rpc/build-debug.sh b/test-components/rpc/build-debug.sh index 88208bc9af..a1d8feb59e 100755 --- a/test-components/rpc/build-debug.sh +++ b/test-components/rpc/build-debug.sh @@ -1,10 +1,18 @@ #!/usr/bin/env sh set -uox pipefail +rm -rf target/wasm32-wasi/debug/rpc:counters-stub +rm -rf target/wasm32-wasi/debug/rpc:ephemeral-stub + cargo component build mkdir -pv target/wasm32-wasi/debug/rpc:counters-stub cp target/wasm32-wasi/debug/counters_stub.wasm target/wasm32-wasi/debug/rpc:counters-stub/stub-counters.wasm -wasm-tools compose -v target/wasm32-wasi/debug/caller.wasm -o target/wasm32-wasi/debug/caller_composed.wasm +wasm-tools compose -v target/wasm32-wasi/debug/caller.wasm -o target/wasm32-wasi/debug/caller_composed1.wasm + +mkdir -pv target/wasm32-wasi/debug/rpc:ephemeral-stub +cp target/wasm32-wasi/debug/ephemeral_stub.wasm target/wasm32-wasi/debug/rpc:ephemeral-stub/stub-ephemeral.wasm +wasm-tools compose -v target/wasm32-wasi/debug/caller_composed1.wasm -o target/wasm32-wasi/debug/caller_composed.wasm cp target/wasm32-wasi/debug/caller_composed.wasm .. cp target/wasm32-wasi/debug/counters.wasm .. +cp target/wasm32-wasi/debug/ephemeral.wasm .. diff --git a/test-components/rpc/build.sh b/test-components/rpc/build.sh index 7dee77900e..5cb4ff2f57 100755 --- a/test-components/rpc/build.sh +++ b/test-components/rpc/build.sh @@ -1,10 +1,18 @@ #!/usr/bin/env sh set -uox pipefail +rm -rf target/wasm32-wasi/release/rpc:counters-stub +rm -rf target/wasm32-wasi/release/rpc:ephemeral-stub + cargo component build --release mkdir -pv target/wasm32-wasi/release/rpc:counters-stub cp target/wasm32-wasi/release/counters_stub.wasm target/wasm32-wasi/release/rpc:counters-stub/stub-counters.wasm -wasm-tools compose -v target/wasm32-wasi/release/caller.wasm -o target/wasm32-wasi/release/caller_composed.wasm +wasm-tools compose -v target/wasm32-wasi/release/caller.wasm -o target/wasm32-wasi/release/caller_composed1.wasm + +mkdir -pv target/wasm32-wasi/release/rpc:ephemeral-stub +cp target/wasm32-wasi/release/ephemeral_stub.wasm target/wasm32-wasi/release/rpc:ephemeral-stub/stub-ephemeral.wasm +wasm-tools compose -v target/wasm32-wasi/release/caller_composed1.wasm -o target/wasm32-wasi/release/caller_composed.wasm cp target/wasm32-wasi/release/caller_composed.wasm .. cp target/wasm32-wasi/release/counters.wasm .. +cp target/wasm32-wasi/release/ephemeral.wasm .. diff --git a/test-components/rpc/caller/Cargo.toml b/test-components/rpc/caller/Cargo.toml index ea785e62a5..0f5942752d 100644 --- a/test-components/rpc/caller/Cargo.toml +++ b/test-components/rpc/caller/Cargo.toml @@ -20,4 +20,6 @@ path = "wit" "golem:rpc" = { path = "wit/deps/wasm-rpc" } "rpc:counters" = { path = "wit/deps/rpc_counters" } "rpc:counters-stub" = { path = "wit/deps/counters-stub" } +"rpc:ephemeral" = { path = "wit/deps/rpc_ephemeral" } +"rpc:ephemeral-stub" = { path = "wit/deps/ephemeral-stub" } "wasi:io" = { path = "wit/deps/io" } diff --git a/test-components/rpc/caller/src/bindings.rs b/test-components/rpc/caller/src/bindings.rs index 15562b555d..b06892f6e2 100644 --- a/test-components/rpc/caller/src/bindings.rs +++ b/test-components/rpc/caller/src/bindings.rs @@ -219,6 +219,69 @@ pub unsafe fn _export_bug_wasm_rpc_i32_cabi(arg0: i32) -> i32 { }; result3 } +#[doc(hidden)] +#[allow(non_snake_case)] +pub unsafe fn _export_ephemeral_test1_cabi() -> *mut u8 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::ephemeral_test1(); + let ptr1 = _RET_AREA.0.as_mut_ptr().cast::(); + let vec5 = result0; + let len5 = vec5.len(); + let layout5 = _rt::alloc::Layout::from_size_align_unchecked(vec5.len() * 16, 4); + let result5 = if layout5.size() != 0 { + let ptr = _rt::alloc::alloc(layout5).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout5); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec5.into_iter().enumerate() { + let base = result5.add(i * 16); + { + let (t2_0, t2_1) = e; + let vec3 = (t2_0.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *base.add(4).cast::() = len3; + *base.add(0).cast::<*mut u8>() = ptr3.cast_mut(); + let vec4 = (t2_1.into_bytes()).into_boxed_slice(); + let ptr4 = vec4.as_ptr().cast::(); + let len4 = vec4.len(); + ::core::mem::forget(vec4); + *base.add(12).cast::() = len4; + *base.add(8).cast::<*mut u8>() = ptr4.cast_mut(); + } + } + *ptr1.add(4).cast::() = len5; + *ptr1.add(0).cast::<*mut u8>() = result5; + ptr1 +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub unsafe fn __post_return_ephemeral_test1(arg0: *mut u8) { + let l4 = *arg0.add(0).cast::<*mut u8>(); + let l5 = *arg0.add(4).cast::(); + let base6 = l4; + let len6 = l5; + for i in 0..len6 { + let base = base6.add(i * 16); + { + let l0 = *base.add(0).cast::<*mut u8>(); + let l1 = *base.add(4).cast::(); + _rt::cabi_dealloc(l0, l1, 1); + let l2 = *base.add(8).cast::<*mut u8>(); + let l3 = *base.add(12).cast::(); + _rt::cabi_dealloc(l2, l3, 1); + } + } + _rt::cabi_dealloc(base6, len6 * 16, 4); +} pub trait Guest { fn test1() -> _rt::Vec<(_rt::String, u64)>; fn test2() -> u64; @@ -226,6 +289,7 @@ pub trait Guest { fn test4() -> (_rt::Vec<_rt::String>, _rt::Vec<(_rt::String, _rt::String)>); fn test5() -> _rt::Vec; fn bug_wasm_rpc_i32(in_: TimelineNode) -> TimelineNode; + fn ephemeral_test1() -> _rt::Vec<(_rt::String, _rt::String)>; } #[doc(hidden)] @@ -268,6 +332,14 @@ macro_rules! __export_world_caller_cabi{ unsafe extern "C" fn export_bug_wasm_rpc_i32(arg0: i32,) -> i32 { $($path_to_types)*::_export_bug_wasm_rpc_i32_cabi::<$ty>(arg0) } + #[export_name = "ephemeral-test1"] + unsafe extern "C" fn export_ephemeral_test1() -> *mut u8 { + $($path_to_types)*::_export_ephemeral_test1_cabi::<$ty>() + } + #[export_name = "cabi_post_ephemeral-test1"] + unsafe extern "C" fn _post_return_ephemeral_test1(arg0: *mut u8,) { + $($path_to_types)*::__post_return_ephemeral_test1::<$ty>(arg0) + } };); } #[doc(hidden)] @@ -4019,6 +4091,393 @@ pub mod rpc { } } } + #[allow(dead_code)] + pub mod ephemeral_stub { + #[allow(dead_code, clippy::all)] + pub mod stub_ephemeral { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type Uri = super::super::super::golem::rpc::types::Uri; + pub type Pollable = super::super::super::wasi::io::poll::Pollable; + + #[derive(Debug)] + #[repr(transparent)] + pub struct FutureGetWorkerNameResult { + handle: _rt::Resource, + } + + impl FutureGetWorkerNameResult { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for FutureGetWorkerNameResult { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[resource-drop]future-get-worker-name-result"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[derive(Debug)] + #[repr(transparent)] + pub struct FutureGetIdempotencyKeyResult { + handle: _rt::Resource, + } + + impl FutureGetIdempotencyKeyResult { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for FutureGetIdempotencyKeyResult { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[resource-drop]future-get-idempotency-key-result"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[derive(Debug)] + #[repr(transparent)] + pub struct Api { + handle: _rt::Resource, + } + + impl Api { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for Api { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[resource-drop]api"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + impl FutureGetWorkerNameResult { + #[allow(unused_unsafe, clippy::all)] + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[method]future-get-worker-name-result.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + impl FutureGetWorkerNameResult { + #[allow(unused_unsafe, clippy::all)] + pub fn get(&self) -> Option<_rt::String> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[method]future-get-worker-name-result.get"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = *ptr0.add(4).cast::<*mut u8>(); + let l3 = *ptr0.add(8).cast::(); + let len4 = l3; + let bytes4 = _rt::Vec::from_raw_parts(l2.cast(), len4, len4); + + _rt::string_lift(bytes4) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl FutureGetIdempotencyKeyResult { + #[allow(unused_unsafe, clippy::all)] + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[method]future-get-idempotency-key-result.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + impl FutureGetIdempotencyKeyResult { + #[allow(unused_unsafe, clippy::all)] + pub fn get(&self) -> Option<_rt::String> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[method]future-get-idempotency-key-result.get"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = *ptr0.add(4).cast::<*mut u8>(); + let l3 = *ptr0.add(8).cast::(); + let len4 = l3; + let bytes4 = _rt::Vec::from_raw_parts(l2.cast(), len4, len4); + + _rt::string_lift(bytes4) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Api { + #[allow(unused_unsafe, clippy::all)] + pub fn new(location: &Uri) -> Self { + unsafe { + let super::super::super::golem::rpc::types::Uri { value: value0 } = + location; + let vec1 = value0; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[constructor]api"] + fn wit_import(_: *mut u8, _: usize) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8, _: usize) -> i32 { + unreachable!() + } + let ret = wit_import(ptr1.cast_mut(), len1); + Api::from_handle(ret as u32) + } + } + } + impl Api { + #[allow(unused_unsafe, clippy::all)] + pub fn blocking_get_worker_name(&self) -> _rt::String { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[method]api.blocking-get-worker-name"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = *ptr0.add(0).cast::<*mut u8>(); + let l2 = *ptr0.add(4).cast::(); + let len3 = l2; + let bytes3 = _rt::Vec::from_raw_parts(l1.cast(), len3, len3); + _rt::string_lift(bytes3) + } + } + } + impl Api { + #[allow(unused_unsafe, clippy::all)] + pub fn get_worker_name(&self) -> FutureGetWorkerNameResult { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[method]api.get-worker-name"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + FutureGetWorkerNameResult::from_handle(ret as u32) + } + } + } + impl Api { + #[allow(unused_unsafe, clippy::all)] + pub fn blocking_get_idempotency_key(&self) -> _rt::String { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[method]api.blocking-get-idempotency-key"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = *ptr0.add(0).cast::<*mut u8>(); + let l2 = *ptr0.add(4).cast::(); + let len3 = l2; + let bytes3 = _rt::Vec::from_raw_parts(l1.cast(), len3, len3); + _rt::string_lift(bytes3) + } + } + } + impl Api { + #[allow(unused_unsafe, clippy::all)] + pub fn get_idempotency_key(&self) -> FutureGetIdempotencyKeyResult { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "rpc:ephemeral-stub/stub-ephemeral")] + extern "C" { + #[link_name = "[method]api.get-idempotency-key"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + FutureGetIdempotencyKeyResult::from_handle(ret as u32) + } + } + } + } + } } #[allow(dead_code)] pub mod wasi { @@ -4511,86 +4970,99 @@ pub(crate) use __export_caller_impl as export; #[cfg(target_arch = "wasm32")] #[link_section = "component-type:wit-bindgen:0.25.0:caller:encoded world"] #[doc(hidden)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 3847] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\x8a\x1d\x01A\x02\x01\ -A\x1f\x01B\x0a\x04\0\x08pollable\x03\x01\x01h\0\x01@\x01\x04self\x01\0\x7f\x04\0\ -\x16[method]pollable.ready\x01\x02\x01@\x01\x04self\x01\x01\0\x04\0\x16[method]p\ -ollable.block\x01\x03\x01p\x01\x01py\x01@\x01\x02in\x04\0\x05\x04\0\x04poll\x01\x06\ -\x03\x01\x12wasi:io/poll@0.2.0\x05\0\x02\x03\0\0\x08pollable\x01B*\x02\x03\x02\x01\ -\x01\x04\0\x08pollable\x03\0\0\x01z\x04\0\x0anode-index\x03\0\x02\x01r\x01\x05va\ -lues\x04\0\x03uri\x03\0\x04\x01p\x03\x01k\x03\x01o\x02y\x07\x01p\x7f\x01j\x01\x07\ -\x01\x07\x01o\x02\x05w\x01q\x16\x0crecord-value\x01\x06\0\x0dvariant-value\x01\x08\ -\0\x0aenum-value\x01y\0\x0bflags-value\x01\x09\0\x0btuple-value\x01\x06\0\x0alis\ -t-value\x01\x06\0\x0coption-value\x01\x07\0\x0cresult-value\x01\x0a\0\x07prim-u8\ -\x01}\0\x08prim-u16\x01{\0\x08prim-u32\x01y\0\x08prim-u64\x01w\0\x07prim-s8\x01~\ -\0\x08prim-s16\x01|\0\x08prim-s32\x01z\0\x08prim-s64\x01x\0\x0cprim-float32\x01v\ -\0\x0cprim-float64\x01u\0\x09prim-char\x01t\0\x09prim-bool\x01\x7f\0\x0bprim-str\ -ing\x01s\0\x06handle\x01\x0b\0\x04\0\x08wit-node\x03\0\x0c\x01p\x0d\x01r\x01\x05\ -nodes\x0e\x04\0\x09wit-value\x03\0\x0f\x01q\x04\x0eprotocol-error\x01s\0\x06deni\ -ed\x01s\0\x09not-found\x01s\0\x15remote-internal-error\x01s\0\x04\0\x09rpc-error\ -\x03\0\x11\x04\0\x08wasm-rpc\x03\x01\x04\0\x14future-invoke-result\x03\x01\x01i\x13\ -\x01@\x01\x08location\x05\0\x15\x04\0\x15[constructor]wasm-rpc\x01\x16\x01h\x13\x01\ -p\x10\x01j\x01\x10\x01\x12\x01@\x03\x04self\x17\x0dfunction-names\x0ffunction-pa\ -rams\x18\0\x19\x04\0![method]wasm-rpc.invoke-and-await\x01\x1a\x01j\0\x01\x12\x01\ -@\x03\x04self\x17\x0dfunction-names\x0ffunction-params\x18\0\x1b\x04\0\x17[metho\ -d]wasm-rpc.invoke\x01\x1c\x01i\x14\x01@\x03\x04self\x17\x0dfunction-names\x0ffun\ -ction-params\x18\0\x1d\x04\0'[method]wasm-rpc.async-invoke-and-await\x01\x1e\x01\ -h\x14\x01i\x01\x01@\x01\x04self\x1f\0\x20\x04\0&[method]future-invoke-result.sub\ -scribe\x01!\x01k\x19\x01@\x01\x04self\x1f\0\"\x04\0\x20[method]future-invoke-res\ -ult.get\x01#\x03\x01\x15golem:rpc/types@0.1.0\x05\x02\x01B\x1c\x04\0\x07counter\x03\ -\x01\x01q\x01\x04leaf\0\0\x04\0\x0dtimeline-node\x03\0\x01\x01i\0\x01@\x01\x04na\ -mes\0\x03\x04\0\x14[constructor]counter\x01\x04\x01h\0\x01@\x02\x04self\x05\x05v\ -aluew\x01\0\x04\0\x16[method]counter.inc-by\x01\x06\x01@\x01\x04self\x05\0w\x04\0\ -\x19[method]counter.get-value\x01\x07\x01ps\x01@\x01\x04self\x05\0\x08\x04\0\x18\ -[method]counter.get-args\x01\x09\x01o\x02ss\x01p\x0a\x01@\x01\x04self\x05\0\x0b\x04\ -\0\x17[method]counter.get-env\x01\x0c\x01@\x01\x05valuew\x01\0\x04\0\x0dinc-glob\ -al-by\x01\x0d\x01@\0\0w\x04\0\x10get-global-value\x01\x0e\x01o\x02sw\x01p\x0f\x01\ -@\0\0\x10\x04\0\x0fget-all-dropped\x01\x11\x01@\x01\x02in\x02\0\x02\x04\0\x10bug\ --wasm-rpc-i32\x01\x12\x03\x01\x10rpc:counters/api\x05\x03\x02\x03\0\x01\x03uri\x02\ -\x03\0\x02\x0dtimeline-node\x01Bc\x02\x03\x02\x01\x04\x04\0\x03uri\x03\0\0\x02\x03\ -\x02\x01\x01\x04\0\x08pollable\x03\0\x02\x02\x03\x02\x01\x05\x04\0\x0dtimeline-n\ -ode\x03\0\x04\x04\0\x1efuture-get-global-value-result\x03\x01\x04\0\x1dfuture-ge\ -t-all-dropped-result\x03\x01\x04\0\x1efuture-bug-wasm-rpc-i32-result\x03\x01\x04\ -\0\x1ffuture-counter-get-value-result\x03\x01\x04\0\x1efuture-counter-get-args-r\ -esult\x03\x01\x04\0\x1dfuture-counter-get-env-result\x03\x01\x04\0\x03api\x03\x01\ -\x04\0\x07counter\x03\x01\x01h\x06\x01i\x03\x01@\x01\x04self\x0e\0\x0f\x04\00[me\ -thod]future-get-global-value-result.subscribe\x01\x10\x01kw\x01@\x01\x04self\x0e\ -\0\x11\x04\0*[method]future-get-global-value-result.get\x01\x12\x01h\x07\x01@\x01\ -\x04self\x13\0\x0f\x04\0/[method]future-get-all-dropped-result.subscribe\x01\x14\ -\x01o\x02sw\x01p\x15\x01k\x16\x01@\x01\x04self\x13\0\x17\x04\0)[method]future-ge\ -t-all-dropped-result.get\x01\x18\x01h\x08\x01@\x01\x04self\x19\0\x0f\x04\00[meth\ -od]future-bug-wasm-rpc-i32-result.subscribe\x01\x1a\x01k\x05\x01@\x01\x04self\x19\ -\0\x1b\x04\0*[method]future-bug-wasm-rpc-i32-result.get\x01\x1c\x01h\x09\x01@\x01\ -\x04self\x1d\0\x0f\x04\01[method]future-counter-get-value-result.subscribe\x01\x1e\ -\x01@\x01\x04self\x1d\0\x11\x04\0+[method]future-counter-get-value-result.get\x01\ -\x1f\x01h\x0a\x01@\x01\x04self\x20\0\x0f\x04\00[method]future-counter-get-args-r\ -esult.subscribe\x01!\x01ps\x01k\"\x01@\x01\x04self\x20\0#\x04\0*[method]future-c\ -ounter-get-args-result.get\x01$\x01h\x0b\x01@\x01\x04self%\0\x0f\x04\0/[method]f\ -uture-counter-get-env-result.subscribe\x01&\x01o\x02ss\x01p'\x01k(\x01@\x01\x04s\ -elf%\0)\x04\0)[method]future-counter-get-env-result.get\x01*\x01i\x0c\x01@\x01\x08\ -location\x01\0+\x04\0\x10[constructor]api\x01,\x01h\x0c\x01@\x02\x04self-\x05val\ -uew\x01\0\x04\0\"[method]api.blocking-inc-global-by\x01.\x04\0\x19[method]api.in\ -c-global-by\x01.\x01@\x01\x04self-\0w\x04\0%[method]api.blocking-get-global-valu\ -e\x01/\x01i\x06\x01@\x01\x04self-\00\x04\0\x1c[method]api.get-global-value\x011\x01\ -@\x01\x04self-\0\x16\x04\0$[method]api.blocking-get-all-dropped\x012\x01i\x07\x01\ -@\x01\x04self-\03\x04\0\x1b[method]api.get-all-dropped\x014\x01@\x02\x04self-\x02\ -in\x05\0\x05\x04\0%[method]api.blocking-bug-wasm-rpc-i32\x015\x01i\x08\x01@\x02\x04\ -self-\x02in\x05\06\x04\0\x1c[method]api.bug-wasm-rpc-i32\x017\x01i\x0d\x01@\x02\x08\ -location\x01\x04names\08\x04\0\x14[constructor]counter\x019\x01h\x0d\x01@\x02\x04\ -self:\x05valuew\x01\0\x04\0\x1f[method]counter.blocking-inc-by\x01;\x04\0\x16[me\ -thod]counter.inc-by\x01;\x01@\x01\x04self:\0w\x04\0\"[method]counter.blocking-ge\ -t-value\x01<\x01i\x09\x01@\x01\x04self:\0=\x04\0\x19[method]counter.get-value\x01\ ->\x01@\x01\x04self:\0\"\x04\0![method]counter.blocking-get-args\x01?\x01i\x0a\x01\ -@\x01\x04self:\0\xc0\0\x04\0\x18[method]counter.get-args\x01A\x01@\x01\x04self:\0\ -(\x04\0\x20[method]counter.blocking-get-env\x01B\x01i\x0b\x01@\x01\x04self:\0\xc3\ -\0\x04\0\x17[method]counter.get-env\x01D\x03\x01\x1frpc:counters-stub/stub-count\ -ers\x05\x06\x02\x03\0\x03\x0dtimeline-node\x03\0\x0dtimeline-node\x03\0\x07\x01o\ -\x02sw\x01p\x09\x01@\0\0\x0a\x04\0\x05test1\x01\x0b\x01@\0\0w\x04\0\x05test2\x01\ -\x0c\x04\0\x05test3\x01\x0c\x01ps\x01o\x02ss\x01p\x0e\x01o\x02\x0d\x0f\x01@\0\0\x10\ -\x04\0\x05test4\x01\x11\x01pw\x01@\0\0\x12\x04\0\x05test5\x01\x13\x01@\x01\x02in\ -\x08\0\x08\x04\0\x10bug-wasm-rpc-i32\x01\x14\x04\x01\x11rpc:caller/caller\x04\0\x0b\ -\x0c\x01\0\x06caller\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-comp\ -onent\x070.208.1\x10wit-bindgen-rust\x060.25.0"; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 4521] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xac\"\x01A\x02\x01A#\ +\x01B\x0a\x04\0\x08pollable\x03\x01\x01h\0\x01@\x01\x04self\x01\0\x7f\x04\0\x16[\ +method]pollable.ready\x01\x02\x01@\x01\x04self\x01\x01\0\x04\0\x16[method]pollab\ +le.block\x01\x03\x01p\x01\x01py\x01@\x01\x02in\x04\0\x05\x04\0\x04poll\x01\x06\x03\ +\x01\x12wasi:io/poll@0.2.0\x05\0\x02\x03\0\0\x08pollable\x01B*\x02\x03\x02\x01\x01\ +\x04\0\x08pollable\x03\0\0\x01z\x04\0\x0anode-index\x03\0\x02\x01r\x01\x05values\ +\x04\0\x03uri\x03\0\x04\x01p\x03\x01k\x03\x01o\x02y\x07\x01p\x7f\x01j\x01\x07\x01\ +\x07\x01o\x02\x05w\x01q\x16\x0crecord-value\x01\x06\0\x0dvariant-value\x01\x08\0\ +\x0aenum-value\x01y\0\x0bflags-value\x01\x09\0\x0btuple-value\x01\x06\0\x0alist-\ +value\x01\x06\0\x0coption-value\x01\x07\0\x0cresult-value\x01\x0a\0\x07prim-u8\x01\ +}\0\x08prim-u16\x01{\0\x08prim-u32\x01y\0\x08prim-u64\x01w\0\x07prim-s8\x01~\0\x08\ +prim-s16\x01|\0\x08prim-s32\x01z\0\x08prim-s64\x01x\0\x0cprim-float32\x01v\0\x0c\ +prim-float64\x01u\0\x09prim-char\x01t\0\x09prim-bool\x01\x7f\0\x0bprim-string\x01\ +s\0\x06handle\x01\x0b\0\x04\0\x08wit-node\x03\0\x0c\x01p\x0d\x01r\x01\x05nodes\x0e\ +\x04\0\x09wit-value\x03\0\x0f\x01q\x04\x0eprotocol-error\x01s\0\x06denied\x01s\0\ +\x09not-found\x01s\0\x15remote-internal-error\x01s\0\x04\0\x09rpc-error\x03\0\x11\ +\x04\0\x08wasm-rpc\x03\x01\x04\0\x14future-invoke-result\x03\x01\x01i\x13\x01@\x01\ +\x08location\x05\0\x15\x04\0\x15[constructor]wasm-rpc\x01\x16\x01h\x13\x01p\x10\x01\ +j\x01\x10\x01\x12\x01@\x03\x04self\x17\x0dfunction-names\x0ffunction-params\x18\0\ +\x19\x04\0![method]wasm-rpc.invoke-and-await\x01\x1a\x01j\0\x01\x12\x01@\x03\x04\ +self\x17\x0dfunction-names\x0ffunction-params\x18\0\x1b\x04\0\x17[method]wasm-rp\ +c.invoke\x01\x1c\x01i\x14\x01@\x03\x04self\x17\x0dfunction-names\x0ffunction-par\ +ams\x18\0\x1d\x04\0'[method]wasm-rpc.async-invoke-and-await\x01\x1e\x01h\x14\x01\ +i\x01\x01@\x01\x04self\x1f\0\x20\x04\0&[method]future-invoke-result.subscribe\x01\ +!\x01k\x19\x01@\x01\x04self\x1f\0\"\x04\0\x20[method]future-invoke-result.get\x01\ +#\x03\x01\x15golem:rpc/types@0.1.0\x05\x02\x01B\x1c\x04\0\x07counter\x03\x01\x01\ +q\x01\x04leaf\0\0\x04\0\x0dtimeline-node\x03\0\x01\x01i\0\x01@\x01\x04names\0\x03\ +\x04\0\x14[constructor]counter\x01\x04\x01h\0\x01@\x02\x04self\x05\x05valuew\x01\ +\0\x04\0\x16[method]counter.inc-by\x01\x06\x01@\x01\x04self\x05\0w\x04\0\x19[met\ +hod]counter.get-value\x01\x07\x01ps\x01@\x01\x04self\x05\0\x08\x04\0\x18[method]\ +counter.get-args\x01\x09\x01o\x02ss\x01p\x0a\x01@\x01\x04self\x05\0\x0b\x04\0\x17\ +[method]counter.get-env\x01\x0c\x01@\x01\x05valuew\x01\0\x04\0\x0dinc-global-by\x01\ +\x0d\x01@\0\0w\x04\0\x10get-global-value\x01\x0e\x01o\x02sw\x01p\x0f\x01@\0\0\x10\ +\x04\0\x0fget-all-dropped\x01\x11\x01@\x01\x02in\x02\0\x02\x04\0\x10bug-wasm-rpc\ +-i32\x01\x12\x03\x01\x10rpc:counters/api\x05\x03\x02\x03\0\x01\x03uri\x02\x03\0\x02\ +\x0dtimeline-node\x01Bc\x02\x03\x02\x01\x04\x04\0\x03uri\x03\0\0\x02\x03\x02\x01\ +\x01\x04\0\x08pollable\x03\0\x02\x02\x03\x02\x01\x05\x04\0\x0dtimeline-node\x03\0\ +\x04\x04\0\x1efuture-get-global-value-result\x03\x01\x04\0\x1dfuture-get-all-dro\ +pped-result\x03\x01\x04\0\x1efuture-bug-wasm-rpc-i32-result\x03\x01\x04\0\x1ffut\ +ure-counter-get-value-result\x03\x01\x04\0\x1efuture-counter-get-args-result\x03\ +\x01\x04\0\x1dfuture-counter-get-env-result\x03\x01\x04\0\x03api\x03\x01\x04\0\x07\ +counter\x03\x01\x01h\x06\x01i\x03\x01@\x01\x04self\x0e\0\x0f\x04\00[method]futur\ +e-get-global-value-result.subscribe\x01\x10\x01kw\x01@\x01\x04self\x0e\0\x11\x04\ +\0*[method]future-get-global-value-result.get\x01\x12\x01h\x07\x01@\x01\x04self\x13\ +\0\x0f\x04\0/[method]future-get-all-dropped-result.subscribe\x01\x14\x01o\x02sw\x01\ +p\x15\x01k\x16\x01@\x01\x04self\x13\0\x17\x04\0)[method]future-get-all-dropped-r\ +esult.get\x01\x18\x01h\x08\x01@\x01\x04self\x19\0\x0f\x04\00[method]future-bug-w\ +asm-rpc-i32-result.subscribe\x01\x1a\x01k\x05\x01@\x01\x04self\x19\0\x1b\x04\0*[\ +method]future-bug-wasm-rpc-i32-result.get\x01\x1c\x01h\x09\x01@\x01\x04self\x1d\0\ +\x0f\x04\01[method]future-counter-get-value-result.subscribe\x01\x1e\x01@\x01\x04\ +self\x1d\0\x11\x04\0+[method]future-counter-get-value-result.get\x01\x1f\x01h\x0a\ +\x01@\x01\x04self\x20\0\x0f\x04\00[method]future-counter-get-args-result.subscri\ +be\x01!\x01ps\x01k\"\x01@\x01\x04self\x20\0#\x04\0*[method]future-counter-get-ar\ +gs-result.get\x01$\x01h\x0b\x01@\x01\x04self%\0\x0f\x04\0/[method]future-counter\ +-get-env-result.subscribe\x01&\x01o\x02ss\x01p'\x01k(\x01@\x01\x04self%\0)\x04\0\ +)[method]future-counter-get-env-result.get\x01*\x01i\x0c\x01@\x01\x08location\x01\ +\0+\x04\0\x10[constructor]api\x01,\x01h\x0c\x01@\x02\x04self-\x05valuew\x01\0\x04\ +\0\"[method]api.blocking-inc-global-by\x01.\x04\0\x19[method]api.inc-global-by\x01\ +.\x01@\x01\x04self-\0w\x04\0%[method]api.blocking-get-global-value\x01/\x01i\x06\ +\x01@\x01\x04self-\00\x04\0\x1c[method]api.get-global-value\x011\x01@\x01\x04sel\ +f-\0\x16\x04\0$[method]api.blocking-get-all-dropped\x012\x01i\x07\x01@\x01\x04se\ +lf-\03\x04\0\x1b[method]api.get-all-dropped\x014\x01@\x02\x04self-\x02in\x05\0\x05\ +\x04\0%[method]api.blocking-bug-wasm-rpc-i32\x015\x01i\x08\x01@\x02\x04self-\x02\ +in\x05\06\x04\0\x1c[method]api.bug-wasm-rpc-i32\x017\x01i\x0d\x01@\x02\x08locati\ +on\x01\x04names\08\x04\0\x14[constructor]counter\x019\x01h\x0d\x01@\x02\x04self:\ +\x05valuew\x01\0\x04\0\x1f[method]counter.blocking-inc-by\x01;\x04\0\x16[method]\ +counter.inc-by\x01;\x01@\x01\x04self:\0w\x04\0\"[method]counter.blocking-get-val\ +ue\x01<\x01i\x09\x01@\x01\x04self:\0=\x04\0\x19[method]counter.get-value\x01>\x01\ +@\x01\x04self:\0\"\x04\0![method]counter.blocking-get-args\x01?\x01i\x0a\x01@\x01\ +\x04self:\0\xc0\0\x04\0\x18[method]counter.get-args\x01A\x01@\x01\x04self:\0(\x04\ +\0\x20[method]counter.blocking-get-env\x01B\x01i\x0b\x01@\x01\x04self:\0\xc3\0\x04\ +\0\x17[method]counter.get-env\x01D\x03\x01\x1frpc:counters-stub/stub-counters\x05\ +\x06\x01B\x20\x02\x03\x02\x01\x04\x04\0\x03uri\x03\0\0\x02\x03\x02\x01\x01\x04\0\ +\x08pollable\x03\0\x02\x04\0\x1dfuture-get-worker-name-result\x03\x01\x04\0!futu\ +re-get-idempotency-key-result\x03\x01\x04\0\x03api\x03\x01\x01h\x04\x01i\x03\x01\ +@\x01\x04self\x07\0\x08\x04\0/[method]future-get-worker-name-result.subscribe\x01\ +\x09\x01ks\x01@\x01\x04self\x07\0\x0a\x04\0)[method]future-get-worker-name-resul\ +t.get\x01\x0b\x01h\x05\x01@\x01\x04self\x0c\0\x08\x04\03[method]future-get-idemp\ +otency-key-result.subscribe\x01\x0d\x01@\x01\x04self\x0c\0\x0a\x04\0-[method]fut\ +ure-get-idempotency-key-result.get\x01\x0e\x01i\x06\x01@\x01\x08location\x01\0\x0f\ +\x04\0\x10[constructor]api\x01\x10\x01h\x06\x01@\x01\x04self\x11\0s\x04\0$[metho\ +d]api.blocking-get-worker-name\x01\x12\x01i\x04\x01@\x01\x04self\x11\0\x13\x04\0\ +\x1b[method]api.get-worker-name\x01\x14\x04\0([method]api.blocking-get-idempoten\ +cy-key\x01\x12\x01i\x05\x01@\x01\x04self\x11\0\x15\x04\0\x1f[method]api.get-idem\ +potency-key\x01\x16\x03\x01!rpc:ephemeral-stub/stub-ephemeral\x05\x07\x02\x03\0\x03\ +\x0dtimeline-node\x03\0\x0dtimeline-node\x03\0\x08\x01o\x02sw\x01p\x0a\x01@\0\0\x0b\ +\x04\0\x05test1\x01\x0c\x01@\0\0w\x04\0\x05test2\x01\x0d\x04\0\x05test3\x01\x0d\x01\ +ps\x01o\x02ss\x01p\x0f\x01o\x02\x0e\x10\x01@\0\0\x11\x04\0\x05test4\x01\x12\x01p\ +w\x01@\0\0\x13\x04\0\x05test5\x01\x14\x01@\x01\x02in\x09\0\x09\x04\0\x10bug-wasm\ +-rpc-i32\x01\x15\x01@\0\0\x10\x04\0\x0fephemeral-test1\x01\x16\x04\x01\x11rpc:ca\ +ller/caller\x04\0\x0b\x0c\x01\0\x06caller\x03\0\0\0G\x09producers\x01\x0cprocess\ +ed-by\x02\x0dwit-component\x070.208.1\x10wit-bindgen-rust\x060.25.0"; #[inline(never)] #[doc(hidden)] diff --git a/test-components/rpc/caller/src/lib.rs b/test-components/rpc/caller/src/lib.rs index fcb671a078..8a623803ae 100644 --- a/test-components/rpc/caller/src/lib.rs +++ b/test-components/rpc/caller/src/lib.rs @@ -2,6 +2,7 @@ mod bindings; use crate::bindings::golem::rpc::types::Uri; use crate::bindings::rpc::counters_stub::stub_counters::{Api, Counter}; +use crate::bindings::rpc::ephemeral_stub::stub_ephemeral::Api as EphemeralApi; use bindings::*; use std::env; @@ -96,6 +97,25 @@ impl Guest for Component { let api = Api::new(&counters_uri); api.blocking_bug_wasm_rpc_i32(in_) } + + fn ephemeral_test1() -> Vec<(String, String)> { + let component_id = + env::var("EPHEMERAL_COMPONENT_ID").expect("EPHEMERAL_COMPONENT_ID not set"); + let ephemeral_uri: Uri = Uri { + value: format!("urn:worker:{component_id}"), + }; + let api1 = EphemeralApi::new(&ephemeral_uri); + let name1: String = api1.blocking_get_worker_name(); + let key1 = api1.blocking_get_idempotency_key(); + let name2 = api1.blocking_get_worker_name(); + let key2 = api1.blocking_get_idempotency_key(); + + let api2 = EphemeralApi::new(&ephemeral_uri); + let name3: String = api2.blocking_get_worker_name(); + let key3: String = api2.blocking_get_idempotency_key(); + + vec![(name1, key1), (name2, key2), (name3, key3)] + } } fn create_use_and_drop_counters(counters_uri: &Uri) { diff --git a/test-components/rpc/caller/wit/caller.wit b/test-components/rpc/caller/wit/caller.wit index d94d92c97c..9ebc339ac5 100644 --- a/test-components/rpc/caller/wit/caller.wit +++ b/test-components/rpc/caller/wit/caller.wit @@ -2,6 +2,8 @@ package rpc:caller; world caller { import rpc:counters-stub/stub-counters; + import rpc:ephemeral-stub/stub-ephemeral; + use rpc:counters-stub/stub-counters.{timeline-node}; export test1: func() -> list>; @@ -11,4 +13,6 @@ world caller { export test5: func() -> list; export bug-wasm-rpc-i32: func(in: timeline-node) -> timeline-node; + + export ephemeral-test1: func() -> list>; } diff --git a/test-components/rpc/caller/wit/deps/ephemeral-stub/stub.wit b/test-components/rpc/caller/wit/deps/ephemeral-stub/stub.wit new file mode 100644 index 0000000000..6d390e49a9 --- /dev/null +++ b/test-components/rpc/caller/wit/deps/ephemeral-stub/stub.wit @@ -0,0 +1,27 @@ +package rpc:ephemeral-stub; + +interface stub-ephemeral { + use golem:rpc/types@0.1.0.{uri}; + use wasi:io/poll@0.2.0.{pollable}; + + resource future-get-worker-name-result { + subscribe: func() -> pollable; + get: func() -> option; + } + resource future-get-idempotency-key-result { + subscribe: func() -> pollable; + get: func() -> option; + } + resource api { + constructor(location: uri); + blocking-get-worker-name: func() -> string; + get-worker-name: func() -> future-get-worker-name-result; + blocking-get-idempotency-key: func() -> string; + get-idempotency-key: func() -> future-get-idempotency-key-result; + } + +} + +world wasm-rpc-stub-ephemeral { + export stub-ephemeral; +} diff --git a/test-components/rpc/caller/wit/deps/rpc_ephemeral/ephemeral.wit b/test-components/rpc/caller/wit/deps/rpc_ephemeral/ephemeral.wit new file mode 100644 index 0000000000..fc59adcf64 --- /dev/null +++ b/test-components/rpc/caller/wit/deps/rpc_ephemeral/ephemeral.wit @@ -0,0 +1,10 @@ +package rpc:ephemeral; + +interface api { + get-worker-name: func() -> string; + get-idempotency-key: func() -> string; +} + +world ephemeral { + export api; +} diff --git a/test-components/rpc/ephemeral-stub/Cargo.toml b/test-components/rpc/ephemeral-stub/Cargo.toml new file mode 100644 index 0000000000..547b144b92 --- /dev/null +++ b/test-components/rpc/ephemeral-stub/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "ephemeral-stub" +version = "0.0.1" +edition = "2021" + +[package.metadata.component] +package = "rpc:ephemeral" + +[package.metadata.component.target] +world = "wasm-rpc-stub-ephemeral" +path = "wit" + +[package.metadata.component.target.dependencies."golem:rpc"] +path = "wit/deps/wasm-rpc" + +[package.metadata.component.target.dependencies."rpc:ephemeral"] +path = "wit/deps/rpc_ephemeral" + +[package.metadata.component.target.dependencies."wasi:io"] +path = "wit/deps/io" + +[dependencies.golem-wasm-rpc] +path = "/Users/vigoo/projects/ziverge/wasm-rpc/wasm-rpc" +features = ["stub"] +default-features = false + +[dependencies.wit-bindgen-rt] +version = "0.26.0" +features = ["bitflags"] + +[lib] +path = "src/lib.rs" +crate-type = ["cdylib"] +required-features = [] + +[profile.release] +opt-level = "s" +lto = true +strip = true diff --git a/test-components/rpc/ephemeral-stub/src/bindings.rs b/test-components/rpc/ephemeral-stub/src/bindings.rs new file mode 100644 index 0000000000..77ea974e64 --- /dev/null +++ b/test-components/rpc/ephemeral-stub/src/bindings.rs @@ -0,0 +1,3662 @@ +// Generated by `wit-bindgen` 0.25.0. DO NOT EDIT! +// Options used: +#[allow(dead_code)] +pub mod golem { + #[allow(dead_code)] + pub mod rpc { + #[allow(dead_code, clippy::all)] + pub mod types { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type Pollable = super::super::super::wasi::io::poll::Pollable; + pub type NodeIndex = i32; + #[derive(Clone)] + pub struct Uri { + pub value: _rt::String, + } + impl ::core::fmt::Debug for Uri { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Uri").field("value", &self.value).finish() + } + } + #[derive(Clone)] + pub enum WitNode { + RecordValue(_rt::Vec), + VariantValue((u32, Option)), + EnumValue(u32), + FlagsValue(_rt::Vec), + TupleValue(_rt::Vec), + ListValue(_rt::Vec), + OptionValue(Option), + ResultValue(Result, Option>), + PrimU8(u8), + PrimU16(u16), + PrimU32(u32), + PrimU64(u64), + PrimS8(i8), + PrimS16(i16), + PrimS32(i32), + PrimS64(i64), + PrimFloat32(f32), + PrimFloat64(f64), + PrimChar(char), + PrimBool(bool), + PrimString(_rt::String), + Handle((Uri, u64)), + } + impl ::core::fmt::Debug for WitNode { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + WitNode::RecordValue(e) => { + f.debug_tuple("WitNode::RecordValue").field(e).finish() + } + WitNode::VariantValue(e) => { + f.debug_tuple("WitNode::VariantValue").field(e).finish() + } + WitNode::EnumValue(e) => { + f.debug_tuple("WitNode::EnumValue").field(e).finish() + } + WitNode::FlagsValue(e) => { + f.debug_tuple("WitNode::FlagsValue").field(e).finish() + } + WitNode::TupleValue(e) => { + f.debug_tuple("WitNode::TupleValue").field(e).finish() + } + WitNode::ListValue(e) => { + f.debug_tuple("WitNode::ListValue").field(e).finish() + } + WitNode::OptionValue(e) => { + f.debug_tuple("WitNode::OptionValue").field(e).finish() + } + WitNode::ResultValue(e) => { + f.debug_tuple("WitNode::ResultValue").field(e).finish() + } + WitNode::PrimU8(e) => f.debug_tuple("WitNode::PrimU8").field(e).finish(), + WitNode::PrimU16(e) => f.debug_tuple("WitNode::PrimU16").field(e).finish(), + WitNode::PrimU32(e) => f.debug_tuple("WitNode::PrimU32").field(e).finish(), + WitNode::PrimU64(e) => f.debug_tuple("WitNode::PrimU64").field(e).finish(), + WitNode::PrimS8(e) => f.debug_tuple("WitNode::PrimS8").field(e).finish(), + WitNode::PrimS16(e) => f.debug_tuple("WitNode::PrimS16").field(e).finish(), + WitNode::PrimS32(e) => f.debug_tuple("WitNode::PrimS32").field(e).finish(), + WitNode::PrimS64(e) => f.debug_tuple("WitNode::PrimS64").field(e).finish(), + WitNode::PrimFloat32(e) => { + f.debug_tuple("WitNode::PrimFloat32").field(e).finish() + } + WitNode::PrimFloat64(e) => { + f.debug_tuple("WitNode::PrimFloat64").field(e).finish() + } + WitNode::PrimChar(e) => { + f.debug_tuple("WitNode::PrimChar").field(e).finish() + } + WitNode::PrimBool(e) => { + f.debug_tuple("WitNode::PrimBool").field(e).finish() + } + WitNode::PrimString(e) => { + f.debug_tuple("WitNode::PrimString").field(e).finish() + } + WitNode::Handle(e) => f.debug_tuple("WitNode::Handle").field(e).finish(), + } + } + } + #[derive(Clone)] + pub struct WitValue { + pub nodes: _rt::Vec, + } + impl ::core::fmt::Debug for WitValue { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("WitValue") + .field("nodes", &self.nodes) + .finish() + } + } + #[derive(Clone)] + pub enum RpcError { + ProtocolError(_rt::String), + Denied(_rt::String), + NotFound(_rt::String), + RemoteInternalError(_rt::String), + } + impl ::core::fmt::Debug for RpcError { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + RpcError::ProtocolError(e) => { + f.debug_tuple("RpcError::ProtocolError").field(e).finish() + } + RpcError::Denied(e) => f.debug_tuple("RpcError::Denied").field(e).finish(), + RpcError::NotFound(e) => { + f.debug_tuple("RpcError::NotFound").field(e).finish() + } + RpcError::RemoteInternalError(e) => f + .debug_tuple("RpcError::RemoteInternalError") + .field(e) + .finish(), + } + } + } + impl ::core::fmt::Display for RpcError { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "{:?}", self) + } + } + + impl std::error::Error for RpcError {} + + #[derive(Debug)] + #[repr(transparent)] + pub struct WasmRpc { + handle: _rt::Resource, + } + + impl WasmRpc { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for WasmRpc { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "golem:rpc/types@0.1.0")] + extern "C" { + #[link_name = "[resource-drop]wasm-rpc"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[derive(Debug)] + #[repr(transparent)] + pub struct FutureInvokeResult { + handle: _rt::Resource, + } + + impl FutureInvokeResult { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for FutureInvokeResult { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "golem:rpc/types@0.1.0")] + extern "C" { + #[link_name = "[resource-drop]future-invoke-result"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + impl WasmRpc { + #[allow(unused_unsafe, clippy::all)] + pub fn new(location: &Uri) -> Self { + unsafe { + let Uri { value: value0 } = location; + let vec1 = value0; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "golem:rpc/types@0.1.0")] + extern "C" { + #[link_name = "[constructor]wasm-rpc"] + fn wit_import(_: *mut u8, _: usize) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8, _: usize) -> i32 { + unreachable!() + } + let ret = wit_import(ptr1.cast_mut(), len1); + WasmRpc::from_handle(ret as u32) + } + } + } + impl WasmRpc { + #[allow(unused_unsafe, clippy::all)] + pub fn invoke_and_await( + &self, + function_name: &str, + function_params: &[WitValue], + ) -> Result { + unsafe { + let mut cleanup_list = _rt::Vec::new(); + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let vec0 = function_name; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let vec12 = function_params; + let len12 = vec12.len(); + let layout12 = + _rt::alloc::Layout::from_size_align_unchecked(vec12.len() * 8, 4); + let result12 = if layout12.size() != 0 { + let ptr = _rt::alloc::alloc(layout12).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout12); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec12.into_iter().enumerate() { + let base = result12.add(i * 8); + { + let WitValue { nodes: nodes1 } = e; + let vec11 = nodes1; + let len11 = vec11.len(); + let layout11 = _rt::alloc::Layout::from_size_align_unchecked( + vec11.len() * 24, + 8, + ); + let result11 = if layout11.size() != 0 { + let ptr = _rt::alloc::alloc(layout11).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout11); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec11.into_iter().enumerate() { + let base = result11.add(i * 24); + { + match e { + WitNode::RecordValue(e) => { + *base.add(0).cast::() = (0i32) as u8; + let vec2 = e; + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + *base.add(12).cast::() = len2; + *base.add(8).cast::<*mut u8>() = ptr2.cast_mut(); + } + WitNode::VariantValue(e) => { + *base.add(0).cast::() = (1i32) as u8; + let (t3_0, t3_1) = e; + *base.add(8).cast::() = _rt::as_i32(t3_0); + match t3_1 { + Some(e) => { + *base.add(12).cast::() = (1i32) as u8; + *base.add(16).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(12).cast::() = (0i32) as u8; + } + }; + } + WitNode::EnumValue(e) => { + *base.add(0).cast::() = (2i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::FlagsValue(e) => { + *base.add(0).cast::() = (3i32) as u8; + let vec4 = e; + let len4 = vec4.len(); + let layout4 = + _rt::alloc::Layout::from_size_align_unchecked( + vec4.len() * 1, + 1, + ); + let result4 = if layout4.size() != 0 { + let ptr = + _rt::alloc::alloc(layout4).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout4); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec4.into_iter().enumerate() { + let base = result4.add(i * 1); + { + *base.add(0).cast::() = (match e { + true => 1, + false => 0, + }) + as u8; + } + } + *base.add(12).cast::() = len4; + *base.add(8).cast::<*mut u8>() = result4; + cleanup_list + .extend_from_slice(&[(result4, layout4)]); + } + WitNode::TupleValue(e) => { + *base.add(0).cast::() = (4i32) as u8; + let vec5 = e; + let ptr5 = vec5.as_ptr().cast::(); + let len5 = vec5.len(); + *base.add(12).cast::() = len5; + *base.add(8).cast::<*mut u8>() = ptr5.cast_mut(); + } + WitNode::ListValue(e) => { + *base.add(0).cast::() = (5i32) as u8; + let vec6 = e; + let ptr6 = vec6.as_ptr().cast::(); + let len6 = vec6.len(); + *base.add(12).cast::() = len6; + *base.add(8).cast::<*mut u8>() = ptr6.cast_mut(); + } + WitNode::OptionValue(e) => { + *base.add(0).cast::() = (6i32) as u8; + match e { + Some(e) => { + *base.add(8).cast::() = (1i32) as u8; + *base.add(12).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(8).cast::() = (0i32) as u8; + } + }; + } + WitNode::ResultValue(e) => { + *base.add(0).cast::() = (7i32) as u8; + match e { + Ok(e) => { + *base.add(8).cast::() = (0i32) as u8; + match e { + Some(e) => { + *base.add(12).cast::() = + (1i32) as u8; + *base.add(16).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(12).cast::() = + (0i32) as u8; + } + }; + } + Err(e) => { + *base.add(8).cast::() = (1i32) as u8; + match e { + Some(e) => { + *base.add(12).cast::() = + (1i32) as u8; + *base.add(16).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(12).cast::() = + (0i32) as u8; + } + }; + } + }; + } + WitNode::PrimU8(e) => { + *base.add(0).cast::() = (8i32) as u8; + *base.add(8).cast::() = (_rt::as_i32(e)) as u8; + } + WitNode::PrimU16(e) => { + *base.add(0).cast::() = (9i32) as u8; + *base.add(8).cast::() = + (_rt::as_i32(e)) as u16; + } + WitNode::PrimU32(e) => { + *base.add(0).cast::() = (10i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::PrimU64(e) => { + *base.add(0).cast::() = (11i32) as u8; + *base.add(8).cast::() = _rt::as_i64(e); + } + WitNode::PrimS8(e) => { + *base.add(0).cast::() = (12i32) as u8; + *base.add(8).cast::() = (_rt::as_i32(e)) as u8; + } + WitNode::PrimS16(e) => { + *base.add(0).cast::() = (13i32) as u8; + *base.add(8).cast::() = + (_rt::as_i32(e)) as u16; + } + WitNode::PrimS32(e) => { + *base.add(0).cast::() = (14i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::PrimS64(e) => { + *base.add(0).cast::() = (15i32) as u8; + *base.add(8).cast::() = _rt::as_i64(e); + } + WitNode::PrimFloat32(e) => { + *base.add(0).cast::() = (16i32) as u8; + *base.add(8).cast::() = _rt::as_f32(e); + } + WitNode::PrimFloat64(e) => { + *base.add(0).cast::() = (17i32) as u8; + *base.add(8).cast::() = _rt::as_f64(e); + } + WitNode::PrimChar(e) => { + *base.add(0).cast::() = (18i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::PrimBool(e) => { + *base.add(0).cast::() = (19i32) as u8; + *base.add(8).cast::() = (match e { + true => 1, + false => 0, + }) + as u8; + } + WitNode::PrimString(e) => { + *base.add(0).cast::() = (20i32) as u8; + let vec7 = e; + let ptr7 = vec7.as_ptr().cast::(); + let len7 = vec7.len(); + *base.add(12).cast::() = len7; + *base.add(8).cast::<*mut u8>() = ptr7.cast_mut(); + } + WitNode::Handle(e) => { + *base.add(0).cast::() = (21i32) as u8; + let (t8_0, t8_1) = e; + let Uri { value: value9 } = t8_0; + let vec10 = value9; + let ptr10 = vec10.as_ptr().cast::(); + let len10 = vec10.len(); + *base.add(12).cast::() = len10; + *base.add(8).cast::<*mut u8>() = ptr10.cast_mut(); + *base.add(16).cast::() = _rt::as_i64(t8_1); + } + } + } + } + *base.add(4).cast::() = len11; + *base.add(0).cast::<*mut u8>() = result11; + cleanup_list.extend_from_slice(&[(result11, layout11)]); + } + } + let ptr13 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "golem:rpc/types@0.1.0")] + extern "C" { + #[link_name = "[method]wasm-rpc.invoke-and-await"] + fn wit_import( + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + ptr0.cast_mut(), + len0, + result12, + len12, + ptr13, + ); + let l14 = i32::from(*ptr13.add(0).cast::()); + if layout12.size() != 0 { + _rt::alloc::dealloc(result12.cast(), layout12); + } + for (ptr, layout) in cleanup_list { + if layout.size() != 0 { + _rt::alloc::dealloc(ptr.cast(), layout); + } + } + match l14 { + 0 => { + let e = { + let l15 = *ptr13.add(4).cast::<*mut u8>(); + let l16 = *ptr13.add(8).cast::(); + let base62 = l15; + let len62 = l16; + let mut result62 = _rt::Vec::with_capacity(len62); + for i in 0..len62 { + let base = base62.add(i * 24); + let e62 = { + let l17 = i32::from(*base.add(0).cast::()); + let v61 = match l17 { + 0 => { + let e61 = { + let l18 = *base.add(8).cast::<*mut u8>(); + let l19 = *base.add(12).cast::(); + let len20 = l19; + + _rt::Vec::from_raw_parts( + l18.cast(), + len20, + len20, + ) + }; + WitNode::RecordValue(e61) + } + 1 => { + let e61 = + { + let l21 = *base.add(8).cast::(); + let l22 = i32::from( + *base.add(12).cast::(), + ); + + (l21 as u32, match l22 { + 0 => None, + 1 => { + let e = { + let l23 = *base.add(16).cast::(); + + l23 + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + }) + }; + WitNode::VariantValue(e61) + } + 2 => { + let e61 = { + let l24 = *base.add(8).cast::(); + + l24 as u32 + }; + WitNode::EnumValue(e61) + } + 3 => { + let e61 = { + let l25 = *base.add(8).cast::<*mut u8>(); + let l26 = *base.add(12).cast::(); + let base28 = l25; + let len28 = l26; + let mut result28 = + _rt::Vec::with_capacity(len28); + for i in 0..len28 { + let base = base28.add(i * 1); + let e28 = { + let l27 = i32::from( + *base.add(0).cast::(), + ); + + _rt::bool_lift(l27 as u8) + }; + result28.push(e28); + } + _rt::cabi_dealloc(base28, len28 * 1, 1); + + result28 + }; + WitNode::FlagsValue(e61) + } + 4 => { + let e61 = { + let l29 = *base.add(8).cast::<*mut u8>(); + let l30 = *base.add(12).cast::(); + let len31 = l30; + + _rt::Vec::from_raw_parts( + l29.cast(), + len31, + len31, + ) + }; + WitNode::TupleValue(e61) + } + 5 => { + let e61 = { + let l32 = *base.add(8).cast::<*mut u8>(); + let l33 = *base.add(12).cast::(); + let len34 = l33; + + _rt::Vec::from_raw_parts( + l32.cast(), + len34, + len34, + ) + }; + WitNode::ListValue(e61) + } + 6 => { + let e61 = { + let l35 = + i32::from(*base.add(8).cast::()); + + match l35 { + 0 => None, + 1 => { + let e = { + let l36 = + *base.add(12).cast::(); + + l36 + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + WitNode::OptionValue(e61) + } + 7 => { + let e61 = { + let l37 = + i32::from(*base.add(8).cast::()); + + match l37 { + 0 => { + let e = { + let l38 = i32::from( + *base.add(12).cast::(), + ); + + match l38 { + 0 => None, + 1 => { + let e = { + let l39 = *base.add(16).cast::(); + + l39 + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + Ok(e) + } + 1 => { + let e = { + let l40 = i32::from( + *base.add(12).cast::(), + ); + + match l40 { + 0 => None, + 1 => { + let e = { + let l41 = *base.add(16).cast::(); + + l41 + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + WitNode::ResultValue(e61) + } + 8 => { + let e61 = { + let l42 = + i32::from(*base.add(8).cast::()); + + l42 as u8 + }; + WitNode::PrimU8(e61) + } + 9 => { + let e61 = { + let l43 = + i32::from(*base.add(8).cast::()); + + l43 as u16 + }; + WitNode::PrimU16(e61) + } + 10 => { + let e61 = { + let l44 = *base.add(8).cast::(); + + l44 as u32 + }; + WitNode::PrimU32(e61) + } + 11 => { + let e61 = { + let l45 = *base.add(8).cast::(); + + l45 as u64 + }; + WitNode::PrimU64(e61) + } + 12 => { + let e61 = { + let l46 = + i32::from(*base.add(8).cast::()); + + l46 as i8 + }; + WitNode::PrimS8(e61) + } + 13 => { + let e61 = { + let l47 = + i32::from(*base.add(8).cast::()); + + l47 as i16 + }; + WitNode::PrimS16(e61) + } + 14 => { + let e61 = { + let l48 = *base.add(8).cast::(); + + l48 + }; + WitNode::PrimS32(e61) + } + 15 => { + let e61 = { + let l49 = *base.add(8).cast::(); + + l49 + }; + WitNode::PrimS64(e61) + } + 16 => { + let e61 = { + let l50 = *base.add(8).cast::(); + + l50 + }; + WitNode::PrimFloat32(e61) + } + 17 => { + let e61 = { + let l51 = *base.add(8).cast::(); + + l51 + }; + WitNode::PrimFloat64(e61) + } + 18 => { + let e61 = { + let l52 = *base.add(8).cast::(); + + _rt::char_lift(l52 as u32) + }; + WitNode::PrimChar(e61) + } + 19 => { + let e61 = { + let l53 = + i32::from(*base.add(8).cast::()); + + _rt::bool_lift(l53 as u8) + }; + WitNode::PrimBool(e61) + } + 20 => { + let e61 = { + let l54 = *base.add(8).cast::<*mut u8>(); + let l55 = *base.add(12).cast::(); + let len56 = l55; + let bytes56 = _rt::Vec::from_raw_parts( + l54.cast(), + len56, + len56, + ); + + _rt::string_lift(bytes56) + }; + WitNode::PrimString(e61) + } + n => { + debug_assert_eq!( + n, 21, + "invalid enum discriminant" + ); + let e61 = { + let l57 = *base.add(8).cast::<*mut u8>(); + let l58 = *base.add(12).cast::(); + let len59 = l58; + let bytes59 = _rt::Vec::from_raw_parts( + l57.cast(), + len59, + len59, + ); + let l60 = *base.add(16).cast::(); + + ( + Uri { + value: _rt::string_lift(bytes59), + }, + l60 as u64, + ) + }; + WitNode::Handle(e61) + } + }; + + v61 + }; + result62.push(e62); + } + _rt::cabi_dealloc(base62, len62 * 24, 8); + + WitValue { nodes: result62 } + }; + Ok(e) + } + 1 => { + let e = { + let l63 = i32::from(*ptr13.add(4).cast::()); + let v76 = match l63 { + 0 => { + let e76 = { + let l64 = *ptr13.add(8).cast::<*mut u8>(); + let l65 = *ptr13.add(12).cast::(); + let len66 = l65; + let bytes66 = _rt::Vec::from_raw_parts( + l64.cast(), + len66, + len66, + ); + + _rt::string_lift(bytes66) + }; + RpcError::ProtocolError(e76) + } + 1 => { + let e76 = { + let l67 = *ptr13.add(8).cast::<*mut u8>(); + let l68 = *ptr13.add(12).cast::(); + let len69 = l68; + let bytes69 = _rt::Vec::from_raw_parts( + l67.cast(), + len69, + len69, + ); + + _rt::string_lift(bytes69) + }; + RpcError::Denied(e76) + } + 2 => { + let e76 = { + let l70 = *ptr13.add(8).cast::<*mut u8>(); + let l71 = *ptr13.add(12).cast::(); + let len72 = l71; + let bytes72 = _rt::Vec::from_raw_parts( + l70.cast(), + len72, + len72, + ); + + _rt::string_lift(bytes72) + }; + RpcError::NotFound(e76) + } + n => { + debug_assert_eq!(n, 3, "invalid enum discriminant"); + let e76 = { + let l73 = *ptr13.add(8).cast::<*mut u8>(); + let l74 = *ptr13.add(12).cast::(); + let len75 = l74; + let bytes75 = _rt::Vec::from_raw_parts( + l73.cast(), + len75, + len75, + ); + + _rt::string_lift(bytes75) + }; + RpcError::RemoteInternalError(e76) + } + }; + + v76 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl WasmRpc { + #[allow(unused_unsafe, clippy::all)] + pub fn invoke( + &self, + function_name: &str, + function_params: &[WitValue], + ) -> Result<(), RpcError> { + unsafe { + let mut cleanup_list = _rt::Vec::new(); + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let vec0 = function_name; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let vec12 = function_params; + let len12 = vec12.len(); + let layout12 = + _rt::alloc::Layout::from_size_align_unchecked(vec12.len() * 8, 4); + let result12 = if layout12.size() != 0 { + let ptr = _rt::alloc::alloc(layout12).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout12); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec12.into_iter().enumerate() { + let base = result12.add(i * 8); + { + let WitValue { nodes: nodes1 } = e; + let vec11 = nodes1; + let len11 = vec11.len(); + let layout11 = _rt::alloc::Layout::from_size_align_unchecked( + vec11.len() * 24, + 8, + ); + let result11 = if layout11.size() != 0 { + let ptr = _rt::alloc::alloc(layout11).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout11); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec11.into_iter().enumerate() { + let base = result11.add(i * 24); + { + match e { + WitNode::RecordValue(e) => { + *base.add(0).cast::() = (0i32) as u8; + let vec2 = e; + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + *base.add(12).cast::() = len2; + *base.add(8).cast::<*mut u8>() = ptr2.cast_mut(); + } + WitNode::VariantValue(e) => { + *base.add(0).cast::() = (1i32) as u8; + let (t3_0, t3_1) = e; + *base.add(8).cast::() = _rt::as_i32(t3_0); + match t3_1 { + Some(e) => { + *base.add(12).cast::() = (1i32) as u8; + *base.add(16).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(12).cast::() = (0i32) as u8; + } + }; + } + WitNode::EnumValue(e) => { + *base.add(0).cast::() = (2i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::FlagsValue(e) => { + *base.add(0).cast::() = (3i32) as u8; + let vec4 = e; + let len4 = vec4.len(); + let layout4 = + _rt::alloc::Layout::from_size_align_unchecked( + vec4.len() * 1, + 1, + ); + let result4 = if layout4.size() != 0 { + let ptr = + _rt::alloc::alloc(layout4).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout4); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec4.into_iter().enumerate() { + let base = result4.add(i * 1); + { + *base.add(0).cast::() = (match e { + true => 1, + false => 0, + }) + as u8; + } + } + *base.add(12).cast::() = len4; + *base.add(8).cast::<*mut u8>() = result4; + cleanup_list + .extend_from_slice(&[(result4, layout4)]); + } + WitNode::TupleValue(e) => { + *base.add(0).cast::() = (4i32) as u8; + let vec5 = e; + let ptr5 = vec5.as_ptr().cast::(); + let len5 = vec5.len(); + *base.add(12).cast::() = len5; + *base.add(8).cast::<*mut u8>() = ptr5.cast_mut(); + } + WitNode::ListValue(e) => { + *base.add(0).cast::() = (5i32) as u8; + let vec6 = e; + let ptr6 = vec6.as_ptr().cast::(); + let len6 = vec6.len(); + *base.add(12).cast::() = len6; + *base.add(8).cast::<*mut u8>() = ptr6.cast_mut(); + } + WitNode::OptionValue(e) => { + *base.add(0).cast::() = (6i32) as u8; + match e { + Some(e) => { + *base.add(8).cast::() = (1i32) as u8; + *base.add(12).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(8).cast::() = (0i32) as u8; + } + }; + } + WitNode::ResultValue(e) => { + *base.add(0).cast::() = (7i32) as u8; + match e { + Ok(e) => { + *base.add(8).cast::() = (0i32) as u8; + match e { + Some(e) => { + *base.add(12).cast::() = + (1i32) as u8; + *base.add(16).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(12).cast::() = + (0i32) as u8; + } + }; + } + Err(e) => { + *base.add(8).cast::() = (1i32) as u8; + match e { + Some(e) => { + *base.add(12).cast::() = + (1i32) as u8; + *base.add(16).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(12).cast::() = + (0i32) as u8; + } + }; + } + }; + } + WitNode::PrimU8(e) => { + *base.add(0).cast::() = (8i32) as u8; + *base.add(8).cast::() = (_rt::as_i32(e)) as u8; + } + WitNode::PrimU16(e) => { + *base.add(0).cast::() = (9i32) as u8; + *base.add(8).cast::() = + (_rt::as_i32(e)) as u16; + } + WitNode::PrimU32(e) => { + *base.add(0).cast::() = (10i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::PrimU64(e) => { + *base.add(0).cast::() = (11i32) as u8; + *base.add(8).cast::() = _rt::as_i64(e); + } + WitNode::PrimS8(e) => { + *base.add(0).cast::() = (12i32) as u8; + *base.add(8).cast::() = (_rt::as_i32(e)) as u8; + } + WitNode::PrimS16(e) => { + *base.add(0).cast::() = (13i32) as u8; + *base.add(8).cast::() = + (_rt::as_i32(e)) as u16; + } + WitNode::PrimS32(e) => { + *base.add(0).cast::() = (14i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::PrimS64(e) => { + *base.add(0).cast::() = (15i32) as u8; + *base.add(8).cast::() = _rt::as_i64(e); + } + WitNode::PrimFloat32(e) => { + *base.add(0).cast::() = (16i32) as u8; + *base.add(8).cast::() = _rt::as_f32(e); + } + WitNode::PrimFloat64(e) => { + *base.add(0).cast::() = (17i32) as u8; + *base.add(8).cast::() = _rt::as_f64(e); + } + WitNode::PrimChar(e) => { + *base.add(0).cast::() = (18i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::PrimBool(e) => { + *base.add(0).cast::() = (19i32) as u8; + *base.add(8).cast::() = (match e { + true => 1, + false => 0, + }) + as u8; + } + WitNode::PrimString(e) => { + *base.add(0).cast::() = (20i32) as u8; + let vec7 = e; + let ptr7 = vec7.as_ptr().cast::(); + let len7 = vec7.len(); + *base.add(12).cast::() = len7; + *base.add(8).cast::<*mut u8>() = ptr7.cast_mut(); + } + WitNode::Handle(e) => { + *base.add(0).cast::() = (21i32) as u8; + let (t8_0, t8_1) = e; + let Uri { value: value9 } = t8_0; + let vec10 = value9; + let ptr10 = vec10.as_ptr().cast::(); + let len10 = vec10.len(); + *base.add(12).cast::() = len10; + *base.add(8).cast::<*mut u8>() = ptr10.cast_mut(); + *base.add(16).cast::() = _rt::as_i64(t8_1); + } + } + } + } + *base.add(4).cast::() = len11; + *base.add(0).cast::<*mut u8>() = result11; + cleanup_list.extend_from_slice(&[(result11, layout11)]); + } + } + let ptr13 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "golem:rpc/types@0.1.0")] + extern "C" { + #[link_name = "[method]wasm-rpc.invoke"] + fn wit_import( + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + ptr0.cast_mut(), + len0, + result12, + len12, + ptr13, + ); + let l14 = i32::from(*ptr13.add(0).cast::()); + if layout12.size() != 0 { + _rt::alloc::dealloc(result12.cast(), layout12); + } + for (ptr, layout) in cleanup_list { + if layout.size() != 0 { + _rt::alloc::dealloc(ptr.cast(), layout); + } + } + match l14 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l15 = i32::from(*ptr13.add(4).cast::()); + let v28 = match l15 { + 0 => { + let e28 = { + let l16 = *ptr13.add(8).cast::<*mut u8>(); + let l17 = *ptr13.add(12).cast::(); + let len18 = l17; + let bytes18 = _rt::Vec::from_raw_parts( + l16.cast(), + len18, + len18, + ); + + _rt::string_lift(bytes18) + }; + RpcError::ProtocolError(e28) + } + 1 => { + let e28 = { + let l19 = *ptr13.add(8).cast::<*mut u8>(); + let l20 = *ptr13.add(12).cast::(); + let len21 = l20; + let bytes21 = _rt::Vec::from_raw_parts( + l19.cast(), + len21, + len21, + ); + + _rt::string_lift(bytes21) + }; + RpcError::Denied(e28) + } + 2 => { + let e28 = { + let l22 = *ptr13.add(8).cast::<*mut u8>(); + let l23 = *ptr13.add(12).cast::(); + let len24 = l23; + let bytes24 = _rt::Vec::from_raw_parts( + l22.cast(), + len24, + len24, + ); + + _rt::string_lift(bytes24) + }; + RpcError::NotFound(e28) + } + n => { + debug_assert_eq!(n, 3, "invalid enum discriminant"); + let e28 = { + let l25 = *ptr13.add(8).cast::<*mut u8>(); + let l26 = *ptr13.add(12).cast::(); + let len27 = l26; + let bytes27 = _rt::Vec::from_raw_parts( + l25.cast(), + len27, + len27, + ); + + _rt::string_lift(bytes27) + }; + RpcError::RemoteInternalError(e28) + } + }; + + v28 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl WasmRpc { + #[allow(unused_unsafe, clippy::all)] + pub fn async_invoke_and_await( + &self, + function_name: &str, + function_params: &[WitValue], + ) -> FutureInvokeResult { + unsafe { + let mut cleanup_list = _rt::Vec::new(); + let vec0 = function_name; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let vec12 = function_params; + let len12 = vec12.len(); + let layout12 = + _rt::alloc::Layout::from_size_align_unchecked(vec12.len() * 8, 4); + let result12 = if layout12.size() != 0 { + let ptr = _rt::alloc::alloc(layout12).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout12); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec12.into_iter().enumerate() { + let base = result12.add(i * 8); + { + let WitValue { nodes: nodes1 } = e; + let vec11 = nodes1; + let len11 = vec11.len(); + let layout11 = _rt::alloc::Layout::from_size_align_unchecked( + vec11.len() * 24, + 8, + ); + let result11 = if layout11.size() != 0 { + let ptr = _rt::alloc::alloc(layout11).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout11); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec11.into_iter().enumerate() { + let base = result11.add(i * 24); + { + match e { + WitNode::RecordValue(e) => { + *base.add(0).cast::() = (0i32) as u8; + let vec2 = e; + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + *base.add(12).cast::() = len2; + *base.add(8).cast::<*mut u8>() = ptr2.cast_mut(); + } + WitNode::VariantValue(e) => { + *base.add(0).cast::() = (1i32) as u8; + let (t3_0, t3_1) = e; + *base.add(8).cast::() = _rt::as_i32(t3_0); + match t3_1 { + Some(e) => { + *base.add(12).cast::() = (1i32) as u8; + *base.add(16).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(12).cast::() = (0i32) as u8; + } + }; + } + WitNode::EnumValue(e) => { + *base.add(0).cast::() = (2i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::FlagsValue(e) => { + *base.add(0).cast::() = (3i32) as u8; + let vec4 = e; + let len4 = vec4.len(); + let layout4 = + _rt::alloc::Layout::from_size_align_unchecked( + vec4.len() * 1, + 1, + ); + let result4 = if layout4.size() != 0 { + let ptr = + _rt::alloc::alloc(layout4).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout4); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec4.into_iter().enumerate() { + let base = result4.add(i * 1); + { + *base.add(0).cast::() = (match e { + true => 1, + false => 0, + }) + as u8; + } + } + *base.add(12).cast::() = len4; + *base.add(8).cast::<*mut u8>() = result4; + cleanup_list + .extend_from_slice(&[(result4, layout4)]); + } + WitNode::TupleValue(e) => { + *base.add(0).cast::() = (4i32) as u8; + let vec5 = e; + let ptr5 = vec5.as_ptr().cast::(); + let len5 = vec5.len(); + *base.add(12).cast::() = len5; + *base.add(8).cast::<*mut u8>() = ptr5.cast_mut(); + } + WitNode::ListValue(e) => { + *base.add(0).cast::() = (5i32) as u8; + let vec6 = e; + let ptr6 = vec6.as_ptr().cast::(); + let len6 = vec6.len(); + *base.add(12).cast::() = len6; + *base.add(8).cast::<*mut u8>() = ptr6.cast_mut(); + } + WitNode::OptionValue(e) => { + *base.add(0).cast::() = (6i32) as u8; + match e { + Some(e) => { + *base.add(8).cast::() = (1i32) as u8; + *base.add(12).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(8).cast::() = (0i32) as u8; + } + }; + } + WitNode::ResultValue(e) => { + *base.add(0).cast::() = (7i32) as u8; + match e { + Ok(e) => { + *base.add(8).cast::() = (0i32) as u8; + match e { + Some(e) => { + *base.add(12).cast::() = + (1i32) as u8; + *base.add(16).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(12).cast::() = + (0i32) as u8; + } + }; + } + Err(e) => { + *base.add(8).cast::() = (1i32) as u8; + match e { + Some(e) => { + *base.add(12).cast::() = + (1i32) as u8; + *base.add(16).cast::() = + _rt::as_i32(e); + } + None => { + *base.add(12).cast::() = + (0i32) as u8; + } + }; + } + }; + } + WitNode::PrimU8(e) => { + *base.add(0).cast::() = (8i32) as u8; + *base.add(8).cast::() = (_rt::as_i32(e)) as u8; + } + WitNode::PrimU16(e) => { + *base.add(0).cast::() = (9i32) as u8; + *base.add(8).cast::() = + (_rt::as_i32(e)) as u16; + } + WitNode::PrimU32(e) => { + *base.add(0).cast::() = (10i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::PrimU64(e) => { + *base.add(0).cast::() = (11i32) as u8; + *base.add(8).cast::() = _rt::as_i64(e); + } + WitNode::PrimS8(e) => { + *base.add(0).cast::() = (12i32) as u8; + *base.add(8).cast::() = (_rt::as_i32(e)) as u8; + } + WitNode::PrimS16(e) => { + *base.add(0).cast::() = (13i32) as u8; + *base.add(8).cast::() = + (_rt::as_i32(e)) as u16; + } + WitNode::PrimS32(e) => { + *base.add(0).cast::() = (14i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::PrimS64(e) => { + *base.add(0).cast::() = (15i32) as u8; + *base.add(8).cast::() = _rt::as_i64(e); + } + WitNode::PrimFloat32(e) => { + *base.add(0).cast::() = (16i32) as u8; + *base.add(8).cast::() = _rt::as_f32(e); + } + WitNode::PrimFloat64(e) => { + *base.add(0).cast::() = (17i32) as u8; + *base.add(8).cast::() = _rt::as_f64(e); + } + WitNode::PrimChar(e) => { + *base.add(0).cast::() = (18i32) as u8; + *base.add(8).cast::() = _rt::as_i32(e); + } + WitNode::PrimBool(e) => { + *base.add(0).cast::() = (19i32) as u8; + *base.add(8).cast::() = (match e { + true => 1, + false => 0, + }) + as u8; + } + WitNode::PrimString(e) => { + *base.add(0).cast::() = (20i32) as u8; + let vec7 = e; + let ptr7 = vec7.as_ptr().cast::(); + let len7 = vec7.len(); + *base.add(12).cast::() = len7; + *base.add(8).cast::<*mut u8>() = ptr7.cast_mut(); + } + WitNode::Handle(e) => { + *base.add(0).cast::() = (21i32) as u8; + let (t8_0, t8_1) = e; + let Uri { value: value9 } = t8_0; + let vec10 = value9; + let ptr10 = vec10.as_ptr().cast::(); + let len10 = vec10.len(); + *base.add(12).cast::() = len10; + *base.add(8).cast::<*mut u8>() = ptr10.cast_mut(); + *base.add(16).cast::() = _rt::as_i64(t8_1); + } + } + } + } + *base.add(4).cast::() = len11; + *base.add(0).cast::<*mut u8>() = result11; + cleanup_list.extend_from_slice(&[(result11, layout11)]); + } + } + + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "golem:rpc/types@0.1.0")] + extern "C" { + #[link_name = "[method]wasm-rpc.async-invoke-and-await"] + fn wit_import( + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + ) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8, _: usize) -> i32 { + unreachable!() + } + let ret = wit_import( + (self).handle() as i32, + ptr0.cast_mut(), + len0, + result12, + len12, + ); + if layout12.size() != 0 { + _rt::alloc::dealloc(result12.cast(), layout12); + } + for (ptr, layout) in cleanup_list { + if layout.size() != 0 { + _rt::alloc::dealloc(ptr.cast(), layout); + } + } + FutureInvokeResult::from_handle(ret as u32) + } + } + } + impl FutureInvokeResult { + #[allow(unused_unsafe, clippy::all)] + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "golem:rpc/types@0.1.0")] + extern "C" { + #[link_name = "[method]future-invoke-result.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + impl FutureInvokeResult { + #[allow(unused_unsafe, clippy::all)] + pub fn get(&self) -> Option> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 20]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 20]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "golem:rpc/types@0.1.0")] + extern "C" { + #[link_name = "[method]future-invoke-result.get"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + + match l2 { + 0 => { + let e = { + let l3 = *ptr0.add(8).cast::<*mut u8>(); + let l4 = *ptr0.add(12).cast::(); + let base50 = l3; + let len50 = l4; + let mut result50 = _rt::Vec::with_capacity(len50); + for i in 0..len50 { + let base = base50.add(i * 24); + let e50 = { + let l5 = + i32::from(*base.add(0).cast::()); + let v49 = match l5 { + 0 => { + let e49 = { + let l6 = *base + .add(8) + .cast::<*mut u8>(); + let l7 = *base + .add(12) + .cast::(); + let len8 = l7; + + _rt::Vec::from_raw_parts( + l6.cast(), + len8, + len8, + ) + }; + WitNode::RecordValue(e49) + } + 1 => { + let e49 = { + let l9 = + *base.add(8).cast::(); + let l10 = i32::from( + *base.add(12).cast::(), + ); + + (l9 as u32, match l10 { + 0 => None, + 1 => { + let e = { + let l11 = *base.add(16).cast::(); + + l11 + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + }) + }; + WitNode::VariantValue(e49) + } + 2 => { + let e49 = { + let l12 = + *base.add(8).cast::(); + + l12 as u32 + }; + WitNode::EnumValue(e49) + } + 3 => { + let e49 = { + let l13 = *base + .add(8) + .cast::<*mut u8>(); + let l14 = *base + .add(12) + .cast::(); + let base16 = l13; + let len16 = l14; + let mut result16 = + _rt::Vec::with_capacity( + len16, + ); + for i in 0..len16 { + let base = + base16.add(i * 1); + let e16 = { + let l15 = i32::from( + *base + .add(0) + .cast::(), + ); + + _rt::bool_lift( + l15 as u8, + ) + }; + result16.push(e16); + } + _rt::cabi_dealloc( + base16, + len16 * 1, + 1, + ); + + result16 + }; + WitNode::FlagsValue(e49) + } + 4 => { + let e49 = { + let l17 = *base + .add(8) + .cast::<*mut u8>(); + let l18 = *base + .add(12) + .cast::(); + let len19 = l18; + + _rt::Vec::from_raw_parts( + l17.cast(), + len19, + len19, + ) + }; + WitNode::TupleValue(e49) + } + 5 => { + let e49 = { + let l20 = *base + .add(8) + .cast::<*mut u8>(); + let l21 = *base + .add(12) + .cast::(); + let len22 = l21; + + _rt::Vec::from_raw_parts( + l20.cast(), + len22, + len22, + ) + }; + WitNode::ListValue(e49) + } + 6 => { + let e49 = { + let l23 = i32::from( + *base.add(8).cast::(), + ); + + match l23 { + 0 => None, + 1 => { + let e = { + let l24 = *base.add(12).cast::(); + + l24 + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + WitNode::OptionValue(e49) + } + 7 => { + let e49 = { + let l25 = i32::from( + *base.add(8).cast::(), + ); + + match l25 { + 0 => { + let e = { + let l26 = i32::from(*base.add(12).cast::()); + + match l26 { + 0 => None, + 1 => { + let e = { + let l27 = *base.add(16).cast::(); + + l27 + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + Ok(e) + } + 1 => { + let e = { + let l28 = i32::from(*base.add(12).cast::()); + + match l28 { + 0 => None, + 1 => { + let e = { + let l29 = *base.add(16).cast::(); + + l29 + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + WitNode::ResultValue(e49) + } + 8 => { + let e49 = { + let l30 = i32::from( + *base.add(8).cast::(), + ); + + l30 as u8 + }; + WitNode::PrimU8(e49) + } + 9 => { + let e49 = { + let l31 = i32::from( + *base.add(8).cast::(), + ); + + l31 as u16 + }; + WitNode::PrimU16(e49) + } + 10 => { + let e49 = { + let l32 = + *base.add(8).cast::(); + + l32 as u32 + }; + WitNode::PrimU32(e49) + } + 11 => { + let e49 = { + let l33 = + *base.add(8).cast::(); + + l33 as u64 + }; + WitNode::PrimU64(e49) + } + 12 => { + let e49 = { + let l34 = i32::from( + *base.add(8).cast::(), + ); + + l34 as i8 + }; + WitNode::PrimS8(e49) + } + 13 => { + let e49 = { + let l35 = i32::from( + *base.add(8).cast::(), + ); + + l35 as i16 + }; + WitNode::PrimS16(e49) + } + 14 => { + let e49 = { + let l36 = + *base.add(8).cast::(); + + l36 + }; + WitNode::PrimS32(e49) + } + 15 => { + let e49 = { + let l37 = + *base.add(8).cast::(); + + l37 + }; + WitNode::PrimS64(e49) + } + 16 => { + let e49 = { + let l38 = + *base.add(8).cast::(); + + l38 + }; + WitNode::PrimFloat32(e49) + } + 17 => { + let e49 = { + let l39 = + *base.add(8).cast::(); + + l39 + }; + WitNode::PrimFloat64(e49) + } + 18 => { + let e49 = { + let l40 = + *base.add(8).cast::(); + + _rt::char_lift(l40 as u32) + }; + WitNode::PrimChar(e49) + } + 19 => { + let e49 = { + let l41 = i32::from( + *base.add(8).cast::(), + ); + + _rt::bool_lift(l41 as u8) + }; + WitNode::PrimBool(e49) + } + 20 => { + let e49 = { + let l42 = *base + .add(8) + .cast::<*mut u8>(); + let l43 = *base + .add(12) + .cast::(); + let len44 = l43; + let bytes44 = + _rt::Vec::from_raw_parts( + l42.cast(), + len44, + len44, + ); + + _rt::string_lift(bytes44) + }; + WitNode::PrimString(e49) + } + n => { + debug_assert_eq!( + n, 21, + "invalid enum discriminant" + ); + let e49 = { + let l45 = *base + .add(8) + .cast::<*mut u8>(); + let l46 = *base + .add(12) + .cast::(); + let len47 = l46; + let bytes47 = + _rt::Vec::from_raw_parts( + l45.cast(), + len47, + len47, + ); + let l48 = + *base.add(16).cast::(); + + ( + Uri { + value: _rt::string_lift( + bytes47, + ), + }, + l48 as u64, + ) + }; + WitNode::Handle(e49) + } + }; + + v49 + }; + result50.push(e50); + } + _rt::cabi_dealloc(base50, len50 * 24, 8); + + WitValue { nodes: result50 } + }; + Ok(e) + } + 1 => { + let e = { + let l51 = i32::from(*ptr0.add(8).cast::()); + let v64 = match l51 { + 0 => { + let e64 = { + let l52 = + *ptr0.add(12).cast::<*mut u8>(); + let l53 = *ptr0.add(16).cast::(); + let len54 = l53; + let bytes54 = _rt::Vec::from_raw_parts( + l52.cast(), + len54, + len54, + ); + + _rt::string_lift(bytes54) + }; + RpcError::ProtocolError(e64) + } + 1 => { + let e64 = { + let l55 = + *ptr0.add(12).cast::<*mut u8>(); + let l56 = *ptr0.add(16).cast::(); + let len57 = l56; + let bytes57 = _rt::Vec::from_raw_parts( + l55.cast(), + len57, + len57, + ); + + _rt::string_lift(bytes57) + }; + RpcError::Denied(e64) + } + 2 => { + let e64 = { + let l58 = + *ptr0.add(12).cast::<*mut u8>(); + let l59 = *ptr0.add(16).cast::(); + let len60 = l59; + let bytes60 = _rt::Vec::from_raw_parts( + l58.cast(), + len60, + len60, + ); + + _rt::string_lift(bytes60) + }; + RpcError::NotFound(e64) + } + n => { + debug_assert_eq!( + n, 3, + "invalid enum discriminant" + ); + let e64 = { + let l61 = + *ptr0.add(12).cast::<*mut u8>(); + let l62 = *ptr0.add(16).cast::(); + let len63 = l62; + let bytes63 = _rt::Vec::from_raw_parts( + l61.cast(), + len63, + len63, + ); + + _rt::string_lift(bytes63) + }; + RpcError::RemoteInternalError(e64) + } + }; + + v64 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + } + } +} +#[allow(dead_code)] +pub mod wasi { + #[allow(dead_code)] + pub mod io { + #[allow(dead_code, clippy::all)] + pub mod poll { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + /// `pollable` epresents a single I/O event which may be ready, or not. + + #[derive(Debug)] + #[repr(transparent)] + pub struct Pollable { + handle: _rt::Resource, + } + + impl Pollable { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for Pollable { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:io/poll@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]pollable"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + impl Pollable { + #[allow(unused_unsafe, clippy::all)] + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + pub fn ready(&self) -> bool { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/poll@0.2.0")] + extern "C" { + #[link_name = "[method]pollable.ready"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + _rt::bool_lift(ret as u8) + } + } + } + impl Pollable { + #[allow(unused_unsafe, clippy::all)] + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + pub fn block(&self) { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/poll@0.2.0")] + extern "C" { + #[link_name = "[method]pollable.block"] + fn wit_import(_: i32); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) { + unreachable!() + } + wit_import((self).handle() as i32); + } + } + } + #[allow(unused_unsafe, clippy::all)] + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// If the list contains more elements than can be indexed with a `u32` + /// value, this function traps. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being reaedy for I/O. + pub fn poll(in_: &[&Pollable]) -> _rt::Vec { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let vec0 = in_; + let len0 = vec0.len(); + let layout0 = _rt::alloc::Layout::from_size_align_unchecked(vec0.len() * 4, 4); + let result0 = if layout0.size() != 0 { + let ptr = _rt::alloc::alloc(layout0).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout0); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec0.into_iter().enumerate() { + let base = result0.add(i * 4); + { + *base.add(0).cast::() = (e).handle() as i32; + } + } + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/poll@0.2.0")] + extern "C" { + #[link_name = "poll"] + fn wit_import(_: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import(result0, len0, ptr1); + let l2 = *ptr1.add(0).cast::<*mut u8>(); + let l3 = *ptr1.add(4).cast::(); + let len4 = l3; + if layout0.size() != 0 { + _rt::alloc::dealloc(result0.cast(), layout0); + } + _rt::Vec::from_raw_parts(l2.cast(), len4, len4) + } + } + } + } +} +#[allow(dead_code)] +pub mod exports { + #[allow(dead_code)] + pub mod rpc { + #[allow(dead_code)] + pub mod ephemeral_stub { + #[allow(dead_code, clippy::all)] + pub mod stub_ephemeral { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::super::__link_custom_section_describing_imports; + use super::super::super::super::_rt; + pub type Uri = super::super::super::super::golem::rpc::types::Uri; + pub type Pollable = super::super::super::super::wasi::io::poll::Pollable; + + #[derive(Debug)] + #[repr(transparent)] + pub struct FutureGetWorkerNameResult { + handle: _rt::Resource, + } + + type _FutureGetWorkerNameResultRep = Option; + + impl FutureGetWorkerNameResult { + /// Creates a new resource from the specified representation. + /// + /// This function will create a new resource handle by moving `val` onto + /// the heap and then passing that heap pointer to the component model to + /// create a handle. The owned handle is then returned as `FutureGetWorkerNameResult`. + pub fn new(val: T) -> Self { + Self::type_guard::(); + let val: _FutureGetWorkerNameResultRep = Some(val); + let ptr: *mut _FutureGetWorkerNameResultRep = + _rt::Box::into_raw(_rt::Box::new(val)); + unsafe { Self::from_handle(T::_resource_new(ptr.cast())) } + } + + /// Gets access to the underlying `T` which represents this resource. + pub fn get(&self) -> &T { + let ptr = unsafe { &*self.as_ptr::() }; + ptr.as_ref().unwrap() + } + + /// Gets mutable access to the underlying `T` which represents this + /// resource. + pub fn get_mut(&mut self) -> &mut T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.as_mut().unwrap() + } + + /// Consumes this resource and returns the underlying `T`. + pub fn into_inner(self) -> T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.take().unwrap() + } + + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + + // It's theoretically possible to implement the `GuestFutureGetWorkerNameResult` trait twice + // so guard against using it with two different types here. + #[doc(hidden)] + fn type_guard() { + use core::any::TypeId; + static mut LAST_TYPE: Option = None; + unsafe { + assert!(!cfg!(target_feature = "threads")); + let id = TypeId::of::(); + match LAST_TYPE { + Some(ty) => assert!( + ty == id, + "cannot use two types with this resource type" + ), + None => LAST_TYPE = Some(id), + } + } + } + + #[doc(hidden)] + pub unsafe fn dtor(handle: *mut u8) { + Self::type_guard::(); + let _ = _rt::Box::from_raw(handle as *mut _FutureGetWorkerNameResultRep); + } + + fn as_ptr( + &self, + ) -> *mut _FutureGetWorkerNameResultRep { + FutureGetWorkerNameResult::type_guard::(); + T::_resource_rep(self.handle()).cast() + } + } + + /// A borrowed version of [`FutureGetWorkerNameResult`] which represents a borrowed value + /// with the lifetime `'a`. + #[derive(Debug)] + #[repr(transparent)] + pub struct FutureGetWorkerNameResultBorrow<'a> { + rep: *mut u8, + _marker: core::marker::PhantomData<&'a FutureGetWorkerNameResult>, + } + + impl<'a> FutureGetWorkerNameResultBorrow<'a> { + #[doc(hidden)] + pub unsafe fn lift(rep: usize) -> Self { + Self { + rep: rep as *mut u8, + _marker: core::marker::PhantomData, + } + } + + /// Gets access to the underlying `T` in this resource. + pub fn get(&self) -> &T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.as_ref().unwrap() + } + + // NB: mutable access is not allowed due to the component model allowing + // multiple borrows of the same resource. + + fn as_ptr(&self) -> *mut _FutureGetWorkerNameResultRep { + FutureGetWorkerNameResult::type_guard::(); + self.rep.cast() + } + } + + unsafe impl _rt::WasmResource for FutureGetWorkerNameResult { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]rpc:ephemeral-stub/stub-ephemeral" + )] + extern "C" { + #[link_name = "[resource-drop]future-get-worker-name-result"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[derive(Debug)] + #[repr(transparent)] + pub struct FutureGetIdempotencyKeyResult { + handle: _rt::Resource, + } + + type _FutureGetIdempotencyKeyResultRep = Option; + + impl FutureGetIdempotencyKeyResult { + /// Creates a new resource from the specified representation. + /// + /// This function will create a new resource handle by moving `val` onto + /// the heap and then passing that heap pointer to the component model to + /// create a handle. The owned handle is then returned as `FutureGetIdempotencyKeyResult`. + pub fn new(val: T) -> Self { + Self::type_guard::(); + let val: _FutureGetIdempotencyKeyResultRep = Some(val); + let ptr: *mut _FutureGetIdempotencyKeyResultRep = + _rt::Box::into_raw(_rt::Box::new(val)); + unsafe { Self::from_handle(T::_resource_new(ptr.cast())) } + } + + /// Gets access to the underlying `T` which represents this resource. + pub fn get(&self) -> &T { + let ptr = unsafe { &*self.as_ptr::() }; + ptr.as_ref().unwrap() + } + + /// Gets mutable access to the underlying `T` which represents this + /// resource. + pub fn get_mut(&mut self) -> &mut T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.as_mut().unwrap() + } + + /// Consumes this resource and returns the underlying `T`. + pub fn into_inner(self) -> T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.take().unwrap() + } + + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + + // It's theoretically possible to implement the `GuestFutureGetIdempotencyKeyResult` trait twice + // so guard against using it with two different types here. + #[doc(hidden)] + fn type_guard() { + use core::any::TypeId; + static mut LAST_TYPE: Option = None; + unsafe { + assert!(!cfg!(target_feature = "threads")); + let id = TypeId::of::(); + match LAST_TYPE { + Some(ty) => assert!( + ty == id, + "cannot use two types with this resource type" + ), + None => LAST_TYPE = Some(id), + } + } + } + + #[doc(hidden)] + pub unsafe fn dtor(handle: *mut u8) { + Self::type_guard::(); + let _ = + _rt::Box::from_raw(handle as *mut _FutureGetIdempotencyKeyResultRep); + } + + fn as_ptr( + &self, + ) -> *mut _FutureGetIdempotencyKeyResultRep { + FutureGetIdempotencyKeyResult::type_guard::(); + T::_resource_rep(self.handle()).cast() + } + } + + /// A borrowed version of [`FutureGetIdempotencyKeyResult`] which represents a borrowed value + /// with the lifetime `'a`. + #[derive(Debug)] + #[repr(transparent)] + pub struct FutureGetIdempotencyKeyResultBorrow<'a> { + rep: *mut u8, + _marker: core::marker::PhantomData<&'a FutureGetIdempotencyKeyResult>, + } + + impl<'a> FutureGetIdempotencyKeyResultBorrow<'a> { + #[doc(hidden)] + pub unsafe fn lift(rep: usize) -> Self { + Self { + rep: rep as *mut u8, + _marker: core::marker::PhantomData, + } + } + + /// Gets access to the underlying `T` in this resource. + pub fn get(&self) -> &T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.as_ref().unwrap() + } + + // NB: mutable access is not allowed due to the component model allowing + // multiple borrows of the same resource. + + fn as_ptr(&self) -> *mut _FutureGetIdempotencyKeyResultRep { + FutureGetIdempotencyKeyResult::type_guard::(); + self.rep.cast() + } + } + + unsafe impl _rt::WasmResource for FutureGetIdempotencyKeyResult { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]rpc:ephemeral-stub/stub-ephemeral" + )] + extern "C" { + #[link_name = "[resource-drop]future-get-idempotency-key-result"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[derive(Debug)] + #[repr(transparent)] + pub struct Api { + handle: _rt::Resource, + } + + type _ApiRep = Option; + + impl Api { + /// Creates a new resource from the specified representation. + /// + /// This function will create a new resource handle by moving `val` onto + /// the heap and then passing that heap pointer to the component model to + /// create a handle. The owned handle is then returned as `Api`. + pub fn new(val: T) -> Self { + Self::type_guard::(); + let val: _ApiRep = Some(val); + let ptr: *mut _ApiRep = _rt::Box::into_raw(_rt::Box::new(val)); + unsafe { Self::from_handle(T::_resource_new(ptr.cast())) } + } + + /// Gets access to the underlying `T` which represents this resource. + pub fn get(&self) -> &T { + let ptr = unsafe { &*self.as_ptr::() }; + ptr.as_ref().unwrap() + } + + /// Gets mutable access to the underlying `T` which represents this + /// resource. + pub fn get_mut(&mut self) -> &mut T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.as_mut().unwrap() + } + + /// Consumes this resource and returns the underlying `T`. + pub fn into_inner(self) -> T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.take().unwrap() + } + + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + + // It's theoretically possible to implement the `GuestApi` trait twice + // so guard against using it with two different types here. + #[doc(hidden)] + fn type_guard() { + use core::any::TypeId; + static mut LAST_TYPE: Option = None; + unsafe { + assert!(!cfg!(target_feature = "threads")); + let id = TypeId::of::(); + match LAST_TYPE { + Some(ty) => assert!( + ty == id, + "cannot use two types with this resource type" + ), + None => LAST_TYPE = Some(id), + } + } + } + + #[doc(hidden)] + pub unsafe fn dtor(handle: *mut u8) { + Self::type_guard::(); + let _ = _rt::Box::from_raw(handle as *mut _ApiRep); + } + + fn as_ptr(&self) -> *mut _ApiRep { + Api::type_guard::(); + T::_resource_rep(self.handle()).cast() + } + } + + /// A borrowed version of [`Api`] which represents a borrowed value + /// with the lifetime `'a`. + #[derive(Debug)] + #[repr(transparent)] + pub struct ApiBorrow<'a> { + rep: *mut u8, + _marker: core::marker::PhantomData<&'a Api>, + } + + impl<'a> ApiBorrow<'a> { + #[doc(hidden)] + pub unsafe fn lift(rep: usize) -> Self { + Self { + rep: rep as *mut u8, + _marker: core::marker::PhantomData, + } + } + + /// Gets access to the underlying `T` in this resource. + pub fn get(&self) -> &T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.as_ref().unwrap() + } + + // NB: mutable access is not allowed due to the component model allowing + // multiple borrows of the same resource. + + fn as_ptr(&self) -> *mut _ApiRep { + Api::type_guard::(); + self.rep.cast() + } + } + + unsafe impl _rt::WasmResource for Api { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]rpc:ephemeral-stub/stub-ephemeral" + )] + extern "C" { + #[link_name = "[resource-drop]api"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_future_get_worker_name_result_subscribe_cabi< + T: GuestFutureGetWorkerNameResult, + >( + arg0: *mut u8, + ) -> i32 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::subscribe( + FutureGetWorkerNameResultBorrow::lift(arg0 as u32 as usize).get(), + ); + (result0).take_handle() as i32 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_future_get_worker_name_result_get_cabi< + T: GuestFutureGetWorkerNameResult, + >( + arg0: *mut u8, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = + T::get(FutureGetWorkerNameResultBorrow::lift(arg0 as u32 as usize).get()); + let ptr1 = _RET_AREA.0.as_mut_ptr().cast::(); + match result0 { + Some(e) => { + *ptr1.add(0).cast::() = (1i32) as u8; + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(8).cast::() = len2; + *ptr1.add(4).cast::<*mut u8>() = ptr2.cast_mut(); + } + None => { + *ptr1.add(0).cast::() = (0i32) as u8; + } + }; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_method_future_get_worker_name_result_get< + T: GuestFutureGetWorkerNameResult, + >( + arg0: *mut u8, + ) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => (), + _ => { + let l1 = *arg0.add(4).cast::<*mut u8>(); + let l2 = *arg0.add(8).cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_future_get_idempotency_key_result_subscribe_cabi< + T: GuestFutureGetIdempotencyKeyResult, + >( + arg0: *mut u8, + ) -> i32 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::subscribe( + FutureGetIdempotencyKeyResultBorrow::lift(arg0 as u32 as usize).get(), + ); + (result0).take_handle() as i32 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_future_get_idempotency_key_result_get_cabi< + T: GuestFutureGetIdempotencyKeyResult, + >( + arg0: *mut u8, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::get( + FutureGetIdempotencyKeyResultBorrow::lift(arg0 as u32 as usize).get(), + ); + let ptr1 = _RET_AREA.0.as_mut_ptr().cast::(); + match result0 { + Some(e) => { + *ptr1.add(0).cast::() = (1i32) as u8; + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(8).cast::() = len2; + *ptr1.add(4).cast::<*mut u8>() = ptr2.cast_mut(); + } + None => { + *ptr1.add(0).cast::() = (0i32) as u8; + } + }; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_method_future_get_idempotency_key_result_get< + T: GuestFutureGetIdempotencyKeyResult, + >( + arg0: *mut u8, + ) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => (), + _ => { + let l1 = *arg0.add(4).cast::<*mut u8>(); + let l2 = *arg0.add(8).cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_constructor_api_cabi( + arg0: *mut u8, + arg1: usize, + ) -> i32 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let len0 = arg1; + let bytes0 = _rt::Vec::from_raw_parts(arg0.cast(), len0, len0); + let result1 = + Api::new(T::new(super::super::super::super::golem::rpc::types::Uri { + value: _rt::string_lift(bytes0), + })); + (result1).take_handle() as i32 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_api_blocking_get_worker_name_cabi( + arg0: *mut u8, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = + T::blocking_get_worker_name(ApiBorrow::lift(arg0 as u32 as usize).get()); + let ptr1 = _RET_AREA.0.as_mut_ptr().cast::(); + let vec2 = (result0.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(4).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_method_api_blocking_get_worker_name( + arg0: *mut u8, + ) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0.add(4).cast::(); + _rt::cabi_dealloc(l0, l1, 1); + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_api_get_worker_name_cabi( + arg0: *mut u8, + ) -> i32 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::get_worker_name(ApiBorrow::lift(arg0 as u32 as usize).get()); + (result0).take_handle() as i32 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_api_blocking_get_idempotency_key_cabi( + arg0: *mut u8, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::blocking_get_idempotency_key( + ApiBorrow::lift(arg0 as u32 as usize).get(), + ); + let ptr1 = _RET_AREA.0.as_mut_ptr().cast::(); + let vec2 = (result0.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(4).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_method_api_blocking_get_idempotency_key( + arg0: *mut u8, + ) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0.add(4).cast::(); + _rt::cabi_dealloc(l0, l1, 1); + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_api_get_idempotency_key_cabi( + arg0: *mut u8, + ) -> i32 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = + T::get_idempotency_key(ApiBorrow::lift(arg0 as u32 as usize).get()); + (result0).take_handle() as i32 + } + pub trait Guest { + type FutureGetWorkerNameResult: GuestFutureGetWorkerNameResult; + type FutureGetIdempotencyKeyResult: GuestFutureGetIdempotencyKeyResult; + type Api: GuestApi; + } + pub trait GuestFutureGetWorkerNameResult: 'static { + #[doc(hidden)] + unsafe fn _resource_new(val: *mut u8) -> u32 + where + Self: Sized, + { + #[cfg(not(target_arch = "wasm32"))] + { + let _ = val; + unreachable!(); + } + + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]rpc:ephemeral-stub/stub-ephemeral" + )] + extern "C" { + #[link_name = "[resource-new]future-get-worker-name-result"] + fn new(_: *mut u8) -> u32; + } + new(val) + } + } + + #[doc(hidden)] + fn _resource_rep(handle: u32) -> *mut u8 + where + Self: Sized, + { + #[cfg(not(target_arch = "wasm32"))] + { + let _ = handle; + unreachable!(); + } + + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]rpc:ephemeral-stub/stub-ephemeral" + )] + extern "C" { + #[link_name = "[resource-rep]future-get-worker-name-result"] + fn rep(_: u32) -> *mut u8; + } + unsafe { rep(handle) } + } + } + + fn subscribe(&self) -> Pollable; + fn get(&self) -> Option<_rt::String>; + } + pub trait GuestFutureGetIdempotencyKeyResult: 'static { + #[doc(hidden)] + unsafe fn _resource_new(val: *mut u8) -> u32 + where + Self: Sized, + { + #[cfg(not(target_arch = "wasm32"))] + { + let _ = val; + unreachable!(); + } + + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]rpc:ephemeral-stub/stub-ephemeral" + )] + extern "C" { + #[link_name = "[resource-new]future-get-idempotency-key-result"] + fn new(_: *mut u8) -> u32; + } + new(val) + } + } + + #[doc(hidden)] + fn _resource_rep(handle: u32) -> *mut u8 + where + Self: Sized, + { + #[cfg(not(target_arch = "wasm32"))] + { + let _ = handle; + unreachable!(); + } + + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]rpc:ephemeral-stub/stub-ephemeral" + )] + extern "C" { + #[link_name = "[resource-rep]future-get-idempotency-key-result"] + fn rep(_: u32) -> *mut u8; + } + unsafe { rep(handle) } + } + } + + fn subscribe(&self) -> Pollable; + fn get(&self) -> Option<_rt::String>; + } + pub trait GuestApi: 'static { + #[doc(hidden)] + unsafe fn _resource_new(val: *mut u8) -> u32 + where + Self: Sized, + { + #[cfg(not(target_arch = "wasm32"))] + { + let _ = val; + unreachable!(); + } + + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]rpc:ephemeral-stub/stub-ephemeral" + )] + extern "C" { + #[link_name = "[resource-new]api"] + fn new(_: *mut u8) -> u32; + } + new(val) + } + } + + #[doc(hidden)] + fn _resource_rep(handle: u32) -> *mut u8 + where + Self: Sized, + { + #[cfg(not(target_arch = "wasm32"))] + { + let _ = handle; + unreachable!(); + } + + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]rpc:ephemeral-stub/stub-ephemeral" + )] + extern "C" { + #[link_name = "[resource-rep]api"] + fn rep(_: u32) -> *mut u8; + } + unsafe { rep(handle) } + } + } + + fn new(location: Uri) -> Self; + fn blocking_get_worker_name(&self) -> _rt::String; + fn get_worker_name(&self) -> FutureGetWorkerNameResult; + fn blocking_get_idempotency_key(&self) -> _rt::String; + fn get_idempotency_key(&self) -> FutureGetIdempotencyKeyResult; + } + #[doc(hidden)] + + macro_rules! __export_rpc_ephemeral_stub_stub_ephemeral_cabi{ + ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { + + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[method]future-get-worker-name-result.subscribe"] + unsafe extern "C" fn export_method_future_get_worker_name_result_subscribe(arg0: *mut u8,) -> i32 { + $($path_to_types)*::_export_method_future_get_worker_name_result_subscribe_cabi::<<$ty as $($path_to_types)*::Guest>::FutureGetWorkerNameResult>(arg0) + } + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[method]future-get-worker-name-result.get"] + unsafe extern "C" fn export_method_future_get_worker_name_result_get(arg0: *mut u8,) -> *mut u8 { + $($path_to_types)*::_export_method_future_get_worker_name_result_get_cabi::<<$ty as $($path_to_types)*::Guest>::FutureGetWorkerNameResult>(arg0) + } + #[export_name = "cabi_post_rpc:ephemeral-stub/stub-ephemeral#[method]future-get-worker-name-result.get"] + unsafe extern "C" fn _post_return_method_future_get_worker_name_result_get(arg0: *mut u8,) { + $($path_to_types)*::__post_return_method_future_get_worker_name_result_get::<<$ty as $($path_to_types)*::Guest>::FutureGetWorkerNameResult>(arg0) + } + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[method]future-get-idempotency-key-result.subscribe"] + unsafe extern "C" fn export_method_future_get_idempotency_key_result_subscribe(arg0: *mut u8,) -> i32 { + $($path_to_types)*::_export_method_future_get_idempotency_key_result_subscribe_cabi::<<$ty as $($path_to_types)*::Guest>::FutureGetIdempotencyKeyResult>(arg0) + } + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[method]future-get-idempotency-key-result.get"] + unsafe extern "C" fn export_method_future_get_idempotency_key_result_get(arg0: *mut u8,) -> *mut u8 { + $($path_to_types)*::_export_method_future_get_idempotency_key_result_get_cabi::<<$ty as $($path_to_types)*::Guest>::FutureGetIdempotencyKeyResult>(arg0) + } + #[export_name = "cabi_post_rpc:ephemeral-stub/stub-ephemeral#[method]future-get-idempotency-key-result.get"] + unsafe extern "C" fn _post_return_method_future_get_idempotency_key_result_get(arg0: *mut u8,) { + $($path_to_types)*::__post_return_method_future_get_idempotency_key_result_get::<<$ty as $($path_to_types)*::Guest>::FutureGetIdempotencyKeyResult>(arg0) + } + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[constructor]api"] + unsafe extern "C" fn export_constructor_api(arg0: *mut u8,arg1: usize,) -> i32 { + $($path_to_types)*::_export_constructor_api_cabi::<<$ty as $($path_to_types)*::Guest>::Api>(arg0, arg1) + } + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[method]api.blocking-get-worker-name"] + unsafe extern "C" fn export_method_api_blocking_get_worker_name(arg0: *mut u8,) -> *mut u8 { + $($path_to_types)*::_export_method_api_blocking_get_worker_name_cabi::<<$ty as $($path_to_types)*::Guest>::Api>(arg0) + } + #[export_name = "cabi_post_rpc:ephemeral-stub/stub-ephemeral#[method]api.blocking-get-worker-name"] + unsafe extern "C" fn _post_return_method_api_blocking_get_worker_name(arg0: *mut u8,) { + $($path_to_types)*::__post_return_method_api_blocking_get_worker_name::<<$ty as $($path_to_types)*::Guest>::Api>(arg0) + } + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[method]api.get-worker-name"] + unsafe extern "C" fn export_method_api_get_worker_name(arg0: *mut u8,) -> i32 { + $($path_to_types)*::_export_method_api_get_worker_name_cabi::<<$ty as $($path_to_types)*::Guest>::Api>(arg0) + } + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[method]api.blocking-get-idempotency-key"] + unsafe extern "C" fn export_method_api_blocking_get_idempotency_key(arg0: *mut u8,) -> *mut u8 { + $($path_to_types)*::_export_method_api_blocking_get_idempotency_key_cabi::<<$ty as $($path_to_types)*::Guest>::Api>(arg0) + } + #[export_name = "cabi_post_rpc:ephemeral-stub/stub-ephemeral#[method]api.blocking-get-idempotency-key"] + unsafe extern "C" fn _post_return_method_api_blocking_get_idempotency_key(arg0: *mut u8,) { + $($path_to_types)*::__post_return_method_api_blocking_get_idempotency_key::<<$ty as $($path_to_types)*::Guest>::Api>(arg0) + } + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[method]api.get-idempotency-key"] + unsafe extern "C" fn export_method_api_get_idempotency_key(arg0: *mut u8,) -> i32 { + $($path_to_types)*::_export_method_api_get_idempotency_key_cabi::<<$ty as $($path_to_types)*::Guest>::Api>(arg0) + } + + const _: () = { + #[doc(hidden)] + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[dtor]future-get-worker-name-result"] + #[allow(non_snake_case)] + unsafe extern "C" fn dtor(rep: *mut u8) { + $($path_to_types)*::FutureGetWorkerNameResult::dtor::< + <$ty as $($path_to_types)*::Guest>::FutureGetWorkerNameResult + >(rep) + } + }; + + + const _: () = { + #[doc(hidden)] + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[dtor]future-get-idempotency-key-result"] + #[allow(non_snake_case)] + unsafe extern "C" fn dtor(rep: *mut u8) { + $($path_to_types)*::FutureGetIdempotencyKeyResult::dtor::< + <$ty as $($path_to_types)*::Guest>::FutureGetIdempotencyKeyResult + >(rep) + } + }; + + + const _: () = { + #[doc(hidden)] + #[export_name = "rpc:ephemeral-stub/stub-ephemeral#[dtor]api"] + #[allow(non_snake_case)] + unsafe extern "C" fn dtor(rep: *mut u8) { + $($path_to_types)*::Api::dtor::< + <$ty as $($path_to_types)*::Guest>::Api + >(rep) + } + }; + + };); + } + #[doc(hidden)] + pub(crate) use __export_rpc_ephemeral_stub_stub_ephemeral_cabi; + #[repr(align(4))] + struct _RetArea([::core::mem::MaybeUninit; 12]); + static mut _RET_AREA: _RetArea = _RetArea([::core::mem::MaybeUninit::uninit(); 12]); + } + } + } +} +mod _rt { + + use core::fmt; + use core::marker; + use core::sync::atomic::{AtomicU32, Ordering::Relaxed}; + + /// A type which represents a component model resource, either imported or + /// exported into this component. + /// + /// This is a low-level wrapper which handles the lifetime of the resource + /// (namely this has a destructor). The `T` provided defines the component model + /// intrinsics that this wrapper uses. + /// + /// One of the chief purposes of this type is to provide `Deref` implementations + /// to access the underlying data when it is owned. + /// + /// This type is primarily used in generated code for exported and imported + /// resources. + #[repr(transparent)] + pub struct Resource { + // NB: This would ideally be `u32` but it is not. The fact that this has + // interior mutability is not exposed in the API of this type except for the + // `take_handle` method which is supposed to in theory be private. + // + // This represents, almost all the time, a valid handle value. When it's + // invalid it's stored as `u32::MAX`. + handle: AtomicU32, + _marker: marker::PhantomData, + } + + /// A trait which all wasm resources implement, namely providing the ability to + /// drop a resource. + /// + /// This generally is implemented by generated code, not user-facing code. + #[allow(clippy::missing_safety_doc)] + pub unsafe trait WasmResource { + /// Invokes the `[resource-drop]...` intrinsic. + unsafe fn drop(handle: u32); + } + + impl Resource { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + debug_assert!(handle != u32::MAX); + Self { + handle: AtomicU32::new(handle), + _marker: marker::PhantomData, + } + } + + /// Takes ownership of the handle owned by `resource`. + /// + /// Note that this ideally would be `into_handle` taking `Resource` by + /// ownership. The code generator does not enable that in all situations, + /// unfortunately, so this is provided instead. + /// + /// Also note that `take_handle` is in theory only ever called on values + /// owned by a generated function. For example a generated function might + /// take `Resource` as an argument but then call `take_handle` on a + /// reference to that argument. In that sense the dynamic nature of + /// `take_handle` should only be exposed internally to generated code, not + /// to user code. + #[doc(hidden)] + pub fn take_handle(resource: &Resource) -> u32 { + resource.handle.swap(u32::MAX, Relaxed) + } + + #[doc(hidden)] + pub fn handle(resource: &Resource) -> u32 { + resource.handle.load(Relaxed) + } + } + + impl fmt::Debug for Resource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Resource") + .field("handle", &self.handle) + .finish() + } + } + + impl Drop for Resource { + fn drop(&mut self) { + unsafe { + match self.handle.load(Relaxed) { + // If this handle was "taken" then don't do anything in the + // destructor. + u32::MAX => {} + + // ... but otherwise do actually destroy it with the imported + // component model intrinsic as defined through `T`. + other => T::drop(other), + } + } + } + } + pub unsafe fn bool_lift(val: u8) -> bool { + if cfg!(debug_assertions) { + match val { + 0 => false, + 1 => true, + _ => panic!("invalid bool discriminant"), + } + } else { + val != 0 + } + } + pub use alloc_crate::alloc; + pub use alloc_crate::string::String; + pub use alloc_crate::vec::Vec; + + pub fn as_i32(t: T) -> i32 { + t.as_i32() + } + + pub trait AsI32 { + fn as_i32(self) -> i32; + } + + impl<'a, T: Copy + AsI32> AsI32 for &'a T { + fn as_i32(self) -> i32 { + (*self).as_i32() + } + } + + impl AsI32 for i32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for char { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for usize { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + pub fn as_i64(t: T) -> i64 { + t.as_i64() + } + + pub trait AsI64 { + fn as_i64(self) -> i64; + } + + impl<'a, T: Copy + AsI64> AsI64 for &'a T { + fn as_i64(self) -> i64 { + (*self).as_i64() + } + } + + impl AsI64 for i64 { + #[inline] + fn as_i64(self) -> i64 { + self as i64 + } + } + + impl AsI64 for u64 { + #[inline] + fn as_i64(self) -> i64 { + self as i64 + } + } + + pub fn as_f32(t: T) -> f32 { + t.as_f32() + } + + pub trait AsF32 { + fn as_f32(self) -> f32; + } + + impl<'a, T: Copy + AsF32> AsF32 for &'a T { + fn as_f32(self) -> f32 { + (*self).as_f32() + } + } + + impl AsF32 for f32 { + #[inline] + fn as_f32(self) -> f32 { + self as f32 + } + } + + pub fn as_f64(t: T) -> f64 { + t.as_f64() + } + + pub trait AsF64 { + fn as_f64(self) -> f64; + } + + impl<'a, T: Copy + AsF64> AsF64 for &'a T { + fn as_f64(self) -> f64 { + (*self).as_f64() + } + } + + impl AsF64 for f64 { + #[inline] + fn as_f64(self) -> f64 { + self as f64 + } + } + pub unsafe fn invalid_enum_discriminant() -> T { + if cfg!(debug_assertions) { + panic!("invalid enum discriminant") + } else { + core::hint::unreachable_unchecked() + } + } + pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { + if size == 0 { + return; + } + let layout = alloc::Layout::from_size_align_unchecked(size, align); + alloc::dealloc(ptr as *mut u8, layout); + } + pub unsafe fn char_lift(val: u32) -> char { + if cfg!(debug_assertions) { + core::char::from_u32(val).unwrap() + } else { + core::char::from_u32_unchecked(val) + } + } + pub unsafe fn string_lift(bytes: Vec) -> String { + if cfg!(debug_assertions) { + String::from_utf8(bytes).unwrap() + } else { + String::from_utf8_unchecked(bytes) + } + } + pub use alloc_crate::boxed::Box; + + #[cfg(target_arch = "wasm32")] + pub fn run_ctors_once() { + wit_bindgen_rt::run_ctors_once(); + } + extern crate alloc as alloc_crate; +} + +/// Generates `#[no_mangle]` functions to export the specified type as the +/// root implementation of all generated traits. +/// +/// For more information see the documentation of `wit_bindgen::generate!`. +/// +/// ```rust +/// # macro_rules! export{ ($($t:tt)*) => (); } +/// # trait Guest {} +/// struct MyType; +/// +/// impl Guest for MyType { +/// // ... +/// } +/// +/// export!(MyType); +/// ``` +#[allow(unused_macros)] +#[doc(hidden)] + +macro_rules! __export_wasm_rpc_stub_ephemeral_impl { + ($ty:ident) => (self::export!($ty with_types_in self);); + ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( + $($path_to_types_root)*::exports::rpc::ephemeral_stub::stub_ephemeral::__export_rpc_ephemeral_stub_stub_ephemeral_cabi!($ty with_types_in $($path_to_types_root)*::exports::rpc::ephemeral_stub::stub_ephemeral); + ) + } +#[doc(inline)] +pub(crate) use __export_wasm_rpc_stub_ephemeral_impl as export; + +#[cfg(target_arch = "wasm32")] +#[link_section = "component-type:wit-bindgen:0.25.0:wasm-rpc-stub-ephemeral:encoded world"] +#[doc(hidden)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1998] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xc0\x0e\x01A\x02\x01\ +A\x08\x01B\x0a\x04\0\x08pollable\x03\x01\x01h\0\x01@\x01\x04self\x01\0\x7f\x04\0\ +\x16[method]pollable.ready\x01\x02\x01@\x01\x04self\x01\x01\0\x04\0\x16[method]p\ +ollable.block\x01\x03\x01p\x01\x01py\x01@\x01\x02in\x04\0\x05\x04\0\x04poll\x01\x06\ +\x03\x01\x12wasi:io/poll@0.2.0\x05\0\x02\x03\0\0\x08pollable\x01B*\x02\x03\x02\x01\ +\x01\x04\0\x08pollable\x03\0\0\x01z\x04\0\x0anode-index\x03\0\x02\x01r\x01\x05va\ +lues\x04\0\x03uri\x03\0\x04\x01p\x03\x01k\x03\x01o\x02y\x07\x01p\x7f\x01j\x01\x07\ +\x01\x07\x01o\x02\x05w\x01q\x16\x0crecord-value\x01\x06\0\x0dvariant-value\x01\x08\ +\0\x0aenum-value\x01y\0\x0bflags-value\x01\x09\0\x0btuple-value\x01\x06\0\x0alis\ +t-value\x01\x06\0\x0coption-value\x01\x07\0\x0cresult-value\x01\x0a\0\x07prim-u8\ +\x01}\0\x08prim-u16\x01{\0\x08prim-u32\x01y\0\x08prim-u64\x01w\0\x07prim-s8\x01~\ +\0\x08prim-s16\x01|\0\x08prim-s32\x01z\0\x08prim-s64\x01x\0\x0cprim-float32\x01v\ +\0\x0cprim-float64\x01u\0\x09prim-char\x01t\0\x09prim-bool\x01\x7f\0\x0bprim-str\ +ing\x01s\0\x06handle\x01\x0b\0\x04\0\x08wit-node\x03\0\x0c\x01p\x0d\x01r\x01\x05\ +nodes\x0e\x04\0\x09wit-value\x03\0\x0f\x01q\x04\x0eprotocol-error\x01s\0\x06deni\ +ed\x01s\0\x09not-found\x01s\0\x15remote-internal-error\x01s\0\x04\0\x09rpc-error\ +\x03\0\x11\x04\0\x08wasm-rpc\x03\x01\x04\0\x14future-invoke-result\x03\x01\x01i\x13\ +\x01@\x01\x08location\x05\0\x15\x04\0\x15[constructor]wasm-rpc\x01\x16\x01h\x13\x01\ +p\x10\x01j\x01\x10\x01\x12\x01@\x03\x04self\x17\x0dfunction-names\x0ffunction-pa\ +rams\x18\0\x19\x04\0![method]wasm-rpc.invoke-and-await\x01\x1a\x01j\0\x01\x12\x01\ +@\x03\x04self\x17\x0dfunction-names\x0ffunction-params\x18\0\x1b\x04\0\x17[metho\ +d]wasm-rpc.invoke\x01\x1c\x01i\x14\x01@\x03\x04self\x17\x0dfunction-names\x0ffun\ +ction-params\x18\0\x1d\x04\0'[method]wasm-rpc.async-invoke-and-await\x01\x1e\x01\ +h\x14\x01i\x01\x01@\x01\x04self\x1f\0\x20\x04\0&[method]future-invoke-result.sub\ +scribe\x01!\x01k\x19\x01@\x01\x04self\x1f\0\"\x04\0\x20[method]future-invoke-res\ +ult.get\x01#\x03\x01\x15golem:rpc/types@0.1.0\x05\x02\x02\x03\0\x01\x03uri\x01B\x20\ +\x02\x03\x02\x01\x03\x04\0\x03uri\x03\0\0\x02\x03\x02\x01\x01\x04\0\x08pollable\x03\ +\0\x02\x04\0\x1dfuture-get-worker-name-result\x03\x01\x04\0!future-get-idempoten\ +cy-key-result\x03\x01\x04\0\x03api\x03\x01\x01h\x04\x01i\x03\x01@\x01\x04self\x07\ +\0\x08\x04\0/[method]future-get-worker-name-result.subscribe\x01\x09\x01ks\x01@\x01\ +\x04self\x07\0\x0a\x04\0)[method]future-get-worker-name-result.get\x01\x0b\x01h\x05\ +\x01@\x01\x04self\x0c\0\x08\x04\03[method]future-get-idempotency-key-result.subs\ +cribe\x01\x0d\x01@\x01\x04self\x0c\0\x0a\x04\0-[method]future-get-idempotency-ke\ +y-result.get\x01\x0e\x01i\x06\x01@\x01\x08location\x01\0\x0f\x04\0\x10[construct\ +or]api\x01\x10\x01h\x06\x01@\x01\x04self\x11\0s\x04\0$[method]api.blocking-get-w\ +orker-name\x01\x12\x01i\x04\x01@\x01\x04self\x11\0\x13\x04\0\x1b[method]api.get-\ +worker-name\x01\x14\x04\0([method]api.blocking-get-idempotency-key\x01\x12\x01i\x05\ +\x01@\x01\x04self\x11\0\x15\x04\0\x1f[method]api.get-idempotency-key\x01\x16\x04\ +\x01!rpc:ephemeral-stub/stub-ephemeral\x05\x04\x04\x01*rpc:ephemeral-stub/wasm-r\ +pc-stub-ephemeral\x04\0\x0b\x1d\x01\0\x17wasm-rpc-stub-ephemeral\x03\0\0\0G\x09p\ +roducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.208.1\x10wit-bindgen-rust\ +\x060.25.0"; + +#[inline(never)] +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/test-components/rpc/ephemeral-stub/src/lib.rs b/test-components/rpc/ephemeral-stub/src/lib.rs new file mode 100644 index 0000000000..eab9217d77 --- /dev/null +++ b/test-components/rpc/ephemeral-stub/src/lib.rs @@ -0,0 +1,143 @@ +#![allow(warnings)] +use golem_wasm_rpc::*; +#[allow(dead_code)] +mod bindings; +pub struct Api { + rpc: WasmRpc, +} +impl Api {} +pub struct FutureGetWorkerNameResult { + pub future_invoke_result: FutureInvokeResult, +} +pub struct FutureGetIdempotencyKeyResult { + pub future_invoke_result: FutureInvokeResult, +} +struct Component; +impl crate::bindings::exports::rpc::ephemeral_stub::stub_ephemeral::Guest for Component { + type Api = crate::Api; + type FutureGetWorkerNameResult = crate::FutureGetWorkerNameResult; + type FutureGetIdempotencyKeyResult = crate::FutureGetIdempotencyKeyResult; +} +impl crate::bindings::exports::rpc::ephemeral_stub::stub_ephemeral::GuestFutureGetWorkerNameResult +for FutureGetWorkerNameResult { + fn subscribe(&self) -> bindings::wasi::io::poll::Pollable { + let pollable = self.future_invoke_result.subscribe(); + let pollable = unsafe { + bindings::wasi::io::poll::Pollable::from_handle(pollable.take_handle()) + }; + pollable + } + fn get(&self) -> Option { + self.future_invoke_result + .get() + .map(|result| { + let result = result + .expect( + &format!( + "Failed to invoke remote {}", + "rpc:ephemeral/api.{get-worker-name}" + ), + ); + (result + .tuple_element(0) + .expect("tuple not found") + .string() + .expect("string not found") + .to_string()) + }) + } +} +impl crate::bindings::exports::rpc::ephemeral_stub::stub_ephemeral::GuestFutureGetIdempotencyKeyResult +for FutureGetIdempotencyKeyResult { + fn subscribe(&self) -> bindings::wasi::io::poll::Pollable { + let pollable = self.future_invoke_result.subscribe(); + let pollable = unsafe { + bindings::wasi::io::poll::Pollable::from_handle(pollable.take_handle()) + }; + pollable + } + fn get(&self) -> Option { + self.future_invoke_result + .get() + .map(|result| { + let result = result + .expect( + &format!( + "Failed to invoke remote {}", + "rpc:ephemeral/api.{get-idempotency-key}" + ), + ); + (result + .tuple_element(0) + .expect("tuple not found") + .string() + .expect("string not found") + .to_string()) + }) + } +} +impl crate::bindings::exports::rpc::ephemeral_stub::stub_ephemeral::GuestApi for Api { + fn new(location: crate::bindings::golem::rpc::types::Uri) -> Self { + let location = golem_wasm_rpc::Uri { + value: location.value, + }; + Self { + rpc: WasmRpc::new(&location), + } + } + fn blocking_get_worker_name(&self) -> String { + let result = self + .rpc + .invoke_and_await("rpc:ephemeral/api.{get-worker-name}", &[]) + .expect( + &format!( + "Failed to invoke-and-await remote {}", + "rpc:ephemeral/api.{get-worker-name}" + ), + ); + (result + .tuple_element(0) + .expect("tuple not found") + .string() + .expect("string not found") + .to_string()) + } + fn get_worker_name( + &self, + ) -> crate::bindings::exports::rpc::ephemeral_stub::stub_ephemeral::FutureGetWorkerNameResult { + let result = self + .rpc + .async_invoke_and_await("rpc:ephemeral/api.{get-worker-name}", &[]); + crate::bindings::exports::rpc::ephemeral_stub::stub_ephemeral::FutureGetWorkerNameResult::new(FutureGetWorkerNameResult { + future_invoke_result: result, + }) + } + fn blocking_get_idempotency_key(&self) -> String { + let result = self + .rpc + .invoke_and_await("rpc:ephemeral/api.{get-idempotency-key}", &[]) + .expect( + &format!( + "Failed to invoke-and-await remote {}", + "rpc:ephemeral/api.{get-idempotency-key}" + ), + ); + (result + .tuple_element(0) + .expect("tuple not found") + .string() + .expect("string not found") + .to_string()) + } + fn get_idempotency_key( + &self, + ) -> crate::bindings::exports::rpc::ephemeral_stub::stub_ephemeral::FutureGetIdempotencyKeyResult { + let result = self + .rpc + .async_invoke_and_await("rpc:ephemeral/api.{get-idempotency-key}", &[]); + crate::bindings::exports::rpc::ephemeral_stub::stub_ephemeral::FutureGetIdempotencyKeyResult::new(FutureGetIdempotencyKeyResult { + future_invoke_result: result, + }) + } +} +bindings::export!(Component with_types_in bindings); diff --git a/test-components/rpc/ephemeral-stub/wit/_stub.wit b/test-components/rpc/ephemeral-stub/wit/_stub.wit new file mode 100644 index 0000000000..6d390e49a9 --- /dev/null +++ b/test-components/rpc/ephemeral-stub/wit/_stub.wit @@ -0,0 +1,27 @@ +package rpc:ephemeral-stub; + +interface stub-ephemeral { + use golem:rpc/types@0.1.0.{uri}; + use wasi:io/poll@0.2.0.{pollable}; + + resource future-get-worker-name-result { + subscribe: func() -> pollable; + get: func() -> option; + } + resource future-get-idempotency-key-result { + subscribe: func() -> pollable; + get: func() -> option; + } + resource api { + constructor(location: uri); + blocking-get-worker-name: func() -> string; + get-worker-name: func() -> future-get-worker-name-result; + blocking-get-idempotency-key: func() -> string; + get-idempotency-key: func() -> future-get-idempotency-key-result; + } + +} + +world wasm-rpc-stub-ephemeral { + export stub-ephemeral; +} diff --git a/test-components/rpc/ephemeral-stub/wit/deps/io/poll.wit b/test-components/rpc/ephemeral-stub/wit/deps/io/poll.wit new file mode 100644 index 0000000000..82fa0f312a --- /dev/null +++ b/test-components/rpc/ephemeral-stub/wit/deps/io/poll.wit @@ -0,0 +1,41 @@ +package wasi:io@0.2.0; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +interface poll { + /// `pollable` epresents a single I/O event which may be ready, or not. + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// If the list contains more elements than can be indexed with a `u32` + /// value, this function traps. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being reaedy for I/O. + poll: func(in: list>) -> list; +} diff --git a/test-components/rpc/ephemeral-stub/wit/deps/rpc_ephemeral/ephemeral.wit b/test-components/rpc/ephemeral-stub/wit/deps/rpc_ephemeral/ephemeral.wit new file mode 100644 index 0000000000..fc59adcf64 --- /dev/null +++ b/test-components/rpc/ephemeral-stub/wit/deps/rpc_ephemeral/ephemeral.wit @@ -0,0 +1,10 @@ +package rpc:ephemeral; + +interface api { + get-worker-name: func() -> string; + get-idempotency-key: func() -> string; +} + +world ephemeral { + export api; +} diff --git a/test-components/rpc/ephemeral-stub/wit/deps/wasm-rpc/wasm-rpc.wit b/test-components/rpc/ephemeral-stub/wit/deps/wasm-rpc/wasm-rpc.wit new file mode 100644 index 0000000000..69e1c8d466 --- /dev/null +++ b/test-components/rpc/ephemeral-stub/wit/deps/wasm-rpc/wasm-rpc.wit @@ -0,0 +1,65 @@ +package golem:rpc@0.1.0; + +interface types { + use wasi:io/poll@0.2.0.{pollable}; + + type node-index = s32; + + record wit-value { + nodes: list, + } + + variant wit-node { + record-value(list), + variant-value(tuple>), + enum-value(u32), + flags-value(list), + tuple-value(list), + list-value(list), + option-value(option), + result-value(result, option>), + prim-u8(u8), + prim-u16(u16), + prim-u32(u32), + prim-u64(u64), + prim-s8(s8), + prim-s16(s16), + prim-s32(s32), + prim-s64(s64), + prim-float32(float32), + prim-float64(float64), + prim-char(char), + prim-bool(bool), + prim-string(string), + handle(tuple) + } + + record uri { + value: string, + } + + variant rpc-error { + protocol-error(string), + denied(string), + not-found(string), + remote-internal-error(string) + } + + resource wasm-rpc { + constructor(location: uri); + + invoke-and-await: func(function-name: string, function-params: list) -> result; + invoke: func(function-name: string, function-params: list) -> result<_, rpc-error>; + + async-invoke-and-await: func(function-name: string, function-params: list) -> future-invoke-result; + } + + resource future-invoke-result { + subscribe: func() -> pollable; + get: func() -> option>; + } +} + +world wit-value { + import types; +} diff --git a/test-components/rpc/ephemeral/Cargo.toml b/test-components/rpc/ephemeral/Cargo.toml new file mode 100644 index 0000000000..4e11b6b499 --- /dev/null +++ b/test-components/rpc/ephemeral/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ephemeral" +version = "0.0.1" +edition = "2021" + +[lib] +path = "src/lib.rs" +crate-type = ["cdylib"] + +[dependencies] +once_cell = "1.17.1" +rand = "0.8.5" +uuid = { version = "1.4.1", features = ["v4"] } +wit-bindgen-rt = { version = "0.26.0", features = ["bitflags"] } + +golem-rust = "1" + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.dependencies] diff --git a/test-components/rpc/ephemeral/src/bindings.rs b/test-components/rpc/ephemeral/src/bindings.rs new file mode 100644 index 0000000000..75b1c5c980 --- /dev/null +++ b/test-components/rpc/ephemeral/src/bindings.rs @@ -0,0 +1,158 @@ +// Generated by `wit-bindgen` 0.25.0. DO NOT EDIT! +// Options used: +#[allow(dead_code)] +pub mod exports { + #[allow(dead_code)] + pub mod rpc { + #[allow(dead_code)] + pub mod ephemeral { + #[allow(dead_code, clippy::all)] + pub mod api { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::super::__link_custom_section_describing_imports; + use super::super::super::super::_rt; + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_get_worker_name_cabi() -> *mut u8 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::get_worker_name(); + let ptr1 = _RET_AREA.0.as_mut_ptr().cast::(); + let vec2 = (result0.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(4).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_get_worker_name(arg0: *mut u8) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0.add(4).cast::(); + _rt::cabi_dealloc(l0, l1, 1); + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_get_idempotency_key_cabi() -> *mut u8 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::get_idempotency_key(); + let ptr1 = _RET_AREA.0.as_mut_ptr().cast::(); + let vec2 = (result0.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(4).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_get_idempotency_key(arg0: *mut u8) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0.add(4).cast::(); + _rt::cabi_dealloc(l0, l1, 1); + } + pub trait Guest { + fn get_worker_name() -> _rt::String; + fn get_idempotency_key() -> _rt::String; + } + #[doc(hidden)] + + macro_rules! __export_rpc_ephemeral_api_cabi{ + ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { + + #[export_name = "rpc:ephemeral/api#get-worker-name"] + unsafe extern "C" fn export_get_worker_name() -> *mut u8 { + $($path_to_types)*::_export_get_worker_name_cabi::<$ty>() + } + #[export_name = "cabi_post_rpc:ephemeral/api#get-worker-name"] + unsafe extern "C" fn _post_return_get_worker_name(arg0: *mut u8,) { + $($path_to_types)*::__post_return_get_worker_name::<$ty>(arg0) + } + #[export_name = "rpc:ephemeral/api#get-idempotency-key"] + unsafe extern "C" fn export_get_idempotency_key() -> *mut u8 { + $($path_to_types)*::_export_get_idempotency_key_cabi::<$ty>() + } + #[export_name = "cabi_post_rpc:ephemeral/api#get-idempotency-key"] + unsafe extern "C" fn _post_return_get_idempotency_key(arg0: *mut u8,) { + $($path_to_types)*::__post_return_get_idempotency_key::<$ty>(arg0) + } + };); + } + #[doc(hidden)] + pub(crate) use __export_rpc_ephemeral_api_cabi; + #[repr(align(4))] + struct _RetArea([::core::mem::MaybeUninit; 8]); + static mut _RET_AREA: _RetArea = _RetArea([::core::mem::MaybeUninit::uninit(); 8]); + } + } + } +} +mod _rt { + + #[cfg(target_arch = "wasm32")] + pub fn run_ctors_once() { + wit_bindgen_rt::run_ctors_once(); + } + pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { + if size == 0 { + return; + } + let layout = alloc::Layout::from_size_align_unchecked(size, align); + alloc::dealloc(ptr as *mut u8, layout); + } + pub use alloc_crate::alloc; + pub use alloc_crate::string::String; + extern crate alloc as alloc_crate; +} + +/// Generates `#[no_mangle]` functions to export the specified type as the +/// root implementation of all generated traits. +/// +/// For more information see the documentation of `wit_bindgen::generate!`. +/// +/// ```rust +/// # macro_rules! export{ ($($t:tt)*) => (); } +/// # trait Guest {} +/// struct MyType; +/// +/// impl Guest for MyType { +/// // ... +/// } +/// +/// export!(MyType); +/// ``` +#[allow(unused_macros)] +#[doc(hidden)] + +macro_rules! __export_ephemeral_impl { + ($ty:ident) => (self::export!($ty with_types_in self);); + ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( + $($path_to_types_root)*::exports::rpc::ephemeral::api::__export_rpc_ephemeral_api_cabi!($ty with_types_in $($path_to_types_root)*::exports::rpc::ephemeral::api); + ) +} +#[doc(inline)] +pub(crate) use __export_ephemeral_impl as export; + +#[cfg(target_arch = "wasm32")] +#[link_section = "component-type:wit-bindgen:0.25.0:ephemeral:encoded world"] +#[doc(hidden)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 235] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07l\x01A\x02\x01A\x02\x01\ +B\x03\x01@\0\0s\x04\0\x0fget-worker-name\x01\0\x04\0\x13get-idempotency-key\x01\0\ +\x04\x01\x11rpc:ephemeral/api\x05\0\x04\x01\x17rpc:ephemeral/ephemeral\x04\0\x0b\ +\x0f\x01\0\x09ephemeral\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-c\ +omponent\x070.208.1\x10wit-bindgen-rust\x060.25.0"; + +#[inline(never)] +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/test-components/rpc/ephemeral/src/lib.rs b/test-components/rpc/ephemeral/src/lib.rs new file mode 100644 index 0000000000..6e0bba394a --- /dev/null +++ b/test-components/rpc/ephemeral/src/lib.rs @@ -0,0 +1,17 @@ +use bindings::exports::rpc::ephemeral::api::Guest; + +mod bindings; + +pub struct Component; + +impl Guest for Component { + fn get_worker_name() -> String { + std::env::var("GOLEM_WORKER_NAME").unwrap() + } + + fn get_idempotency_key() -> String { + golem_rust::generate_idempotency_key().to_string() + } +} + +bindings::export!(Component with_types_in bindings); diff --git a/test-components/rpc/ephemeral/wit/ephemeral.wit b/test-components/rpc/ephemeral/wit/ephemeral.wit new file mode 100644 index 0000000000..fc59adcf64 --- /dev/null +++ b/test-components/rpc/ephemeral/wit/ephemeral.wit @@ -0,0 +1,10 @@ +package rpc:ephemeral; + +interface api { + get-worker-name: func() -> string; + get-idempotency-key: func() -> string; +} + +world ephemeral { + export api; +} diff --git a/test-components/rpc/stubgen.sh b/test-components/rpc/stubgen.sh index bd1f30e2bf..5ed50906b4 100755 --- a/test-components/rpc/stubgen.sh +++ b/test-components/rpc/stubgen.sh @@ -8,3 +8,9 @@ mkdir -pv caller/wit/deps cp -rv counters-stub/wit/deps/* caller/wit/deps mkdir -pv caller/wit/deps/counters-stub cp counters-stub/wit/_stub.wit caller/wit/deps/counters-stub/stub.wit + +rm -rf ephemeral-stub +wasm-rpc-stubgen generate --source-wit-root ephemeral/wit --dest-crate-root ephemeral-stub --wasm-rpc-path-override /Users/vigoo/projects/ziverge/wasm-rpc/wasm-rpc +cp -rv ephemeral-stub/wit/deps/* caller/wit/deps +mkdir -pv caller/wit/deps/ephemeral-stub +cp ephemeral-stub/wit/_stub.wit caller/wit/deps/ephemeral-stub/stub.wit diff --git a/test-components/runtime-service.wasm b/test-components/runtime-service.wasm index 14b0b90e71..81e64f2095 100755 Binary files a/test-components/runtime-service.wasm and b/test-components/runtime-service.wasm differ diff --git a/test-components/runtime-service/src/bindings.rs b/test-components/runtime-service/src/bindings.rs index dd363ce253..06dd7223cd 100644 --- a/test-components/runtime-service/src/bindings.rs +++ b/test-components/runtime-service/src/bindings.rs @@ -11565,6 +11565,7 @@ pub mod exports { super::super::super::super::golem::api::host::WorkerAnyFilter; pub type WorkerMetadata = super::super::super::super::golem::api::host::WorkerMetadata; + pub type Uuid = super::super::super::super::golem::api::host::Uuid; #[doc(hidden)] #[allow(non_snake_case)] pub unsafe fn _export_get_self_uri_cabi( @@ -12310,6 +12311,28 @@ pub mod exports { super::super::super::super::golem::api::host::UpdateMode::_lift(arg5 as u8), ); } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_generate_idempotency_keys_cabi() -> *mut u8 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::generate_idempotency_keys(); + let ptr1 = _RET_AREA.0.as_mut_ptr().cast::(); + let (t2_0, t2_1) = result0; + let super::super::super::super::golem::api::host::Uuid { + high_bits: high_bits3, + low_bits: low_bits3, + } = t2_0; + *ptr1.add(0).cast::() = _rt::as_i64(high_bits3); + *ptr1.add(8).cast::() = _rt::as_i64(low_bits3); + let super::super::super::super::golem::api::host::Uuid { + high_bits: high_bits4, + low_bits: low_bits4, + } = t2_1; + *ptr1.add(16).cast::() = _rt::as_i64(high_bits4); + *ptr1.add(24).cast::() = _rt::as_i64(low_bits4); + ptr1 + } pub trait Guest { fn get_self_uri(function_name: _rt::String) -> _rt::String; fn jump() -> u64; @@ -12330,74 +12353,79 @@ pub mod exports { component_version: ComponentVersion, update_mode: UpdateMode, ); + fn generate_idempotency_keys() -> (Uuid, Uuid); } #[doc(hidden)] macro_rules! __export_golem_it_api_cabi{ - ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { - - #[export_name = "golem:it/api#get-self-uri"] - unsafe extern "C" fn export_get_self_uri(arg0: *mut u8,arg1: usize,) -> *mut u8 { - $($path_to_types)*::_export_get_self_uri_cabi::<$ty>(arg0, arg1) - } - #[export_name = "cabi_post_golem:it/api#get-self-uri"] - unsafe extern "C" fn _post_return_get_self_uri(arg0: *mut u8,) { - $($path_to_types)*::__post_return_get_self_uri::<$ty>(arg0) - } - #[export_name = "golem:it/api#jump"] - unsafe extern "C" fn export_jump() -> i64 { - $($path_to_types)*::_export_jump_cabi::<$ty>() - } - #[export_name = "golem:it/api#fail-with-custom-max-retries"] - unsafe extern "C" fn export_fail_with_custom_max_retries(arg0: i64,) { - $($path_to_types)*::_export_fail_with_custom_max_retries_cabi::<$ty>(arg0) - } - #[export_name = "golem:it/api#explicit-commit"] - unsafe extern "C" fn export_explicit_commit(arg0: i32,) { - $($path_to_types)*::_export_explicit_commit_cabi::<$ty>(arg0) - } - #[export_name = "golem:it/api#atomic-region"] - unsafe extern "C" fn export_atomic_region() { - $($path_to_types)*::_export_atomic_region_cabi::<$ty>() - } - #[export_name = "golem:it/api#idempotence-flag"] - unsafe extern "C" fn export_idempotence_flag(arg0: i32,) { - $($path_to_types)*::_export_idempotence_flag_cabi::<$ty>(arg0) - } - #[export_name = "golem:it/api#persist-nothing"] - unsafe extern "C" fn export_persist_nothing() { - $($path_to_types)*::_export_persist_nothing_cabi::<$ty>() - } - #[export_name = "golem:it/api#get-workers"] - unsafe extern "C" fn export_get_workers(arg0: i64,arg1: i64,arg2: i32,arg3: *mut u8,arg4: usize,arg5: i32,) -> *mut u8 { - $($path_to_types)*::_export_get_workers_cabi::<$ty>(arg0, arg1, arg2, arg3, arg4, arg5) - } - #[export_name = "cabi_post_golem:it/api#get-workers"] - unsafe extern "C" fn _post_return_get_workers(arg0: *mut u8,) { - $($path_to_types)*::__post_return_get_workers::<$ty>(arg0) - } - #[export_name = "golem:it/api#get-self-metadata"] - unsafe extern "C" fn export_get_self_metadata() -> *mut u8 { - $($path_to_types)*::_export_get_self_metadata_cabi::<$ty>() - } - #[export_name = "cabi_post_golem:it/api#get-self-metadata"] - unsafe extern "C" fn _post_return_get_self_metadata(arg0: *mut u8,) { - $($path_to_types)*::__post_return_get_self_metadata::<$ty>(arg0) - } - #[export_name = "golem:it/api#get-worker-metadata"] - unsafe extern "C" fn export_get_worker_metadata(arg0: i64,arg1: i64,arg2: *mut u8,arg3: usize,) -> *mut u8 { - $($path_to_types)*::_export_get_worker_metadata_cabi::<$ty>(arg0, arg1, arg2, arg3) - } - #[export_name = "cabi_post_golem:it/api#get-worker-metadata"] - unsafe extern "C" fn _post_return_get_worker_metadata(arg0: *mut u8,) { - $($path_to_types)*::__post_return_get_worker_metadata::<$ty>(arg0) - } - #[export_name = "golem:it/api#update-worker"] - unsafe extern "C" fn export_update_worker(arg0: i64,arg1: i64,arg2: *mut u8,arg3: usize,arg4: i64,arg5: i32,) { - $($path_to_types)*::_export_update_worker_cabi::<$ty>(arg0, arg1, arg2, arg3, arg4, arg5) - } - };); - } + ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { + + #[export_name = "golem:it/api#get-self-uri"] + unsafe extern "C" fn export_get_self_uri(arg0: *mut u8,arg1: usize,) -> *mut u8 { + $($path_to_types)*::_export_get_self_uri_cabi::<$ty>(arg0, arg1) + } + #[export_name = "cabi_post_golem:it/api#get-self-uri"] + unsafe extern "C" fn _post_return_get_self_uri(arg0: *mut u8,) { + $($path_to_types)*::__post_return_get_self_uri::<$ty>(arg0) + } + #[export_name = "golem:it/api#jump"] + unsafe extern "C" fn export_jump() -> i64 { + $($path_to_types)*::_export_jump_cabi::<$ty>() + } + #[export_name = "golem:it/api#fail-with-custom-max-retries"] + unsafe extern "C" fn export_fail_with_custom_max_retries(arg0: i64,) { + $($path_to_types)*::_export_fail_with_custom_max_retries_cabi::<$ty>(arg0) + } + #[export_name = "golem:it/api#explicit-commit"] + unsafe extern "C" fn export_explicit_commit(arg0: i32,) { + $($path_to_types)*::_export_explicit_commit_cabi::<$ty>(arg0) + } + #[export_name = "golem:it/api#atomic-region"] + unsafe extern "C" fn export_atomic_region() { + $($path_to_types)*::_export_atomic_region_cabi::<$ty>() + } + #[export_name = "golem:it/api#idempotence-flag"] + unsafe extern "C" fn export_idempotence_flag(arg0: i32,) { + $($path_to_types)*::_export_idempotence_flag_cabi::<$ty>(arg0) + } + #[export_name = "golem:it/api#persist-nothing"] + unsafe extern "C" fn export_persist_nothing() { + $($path_to_types)*::_export_persist_nothing_cabi::<$ty>() + } + #[export_name = "golem:it/api#get-workers"] + unsafe extern "C" fn export_get_workers(arg0: i64,arg1: i64,arg2: i32,arg3: *mut u8,arg4: usize,arg5: i32,) -> *mut u8 { + $($path_to_types)*::_export_get_workers_cabi::<$ty>(arg0, arg1, arg2, arg3, arg4, arg5) + } + #[export_name = "cabi_post_golem:it/api#get-workers"] + unsafe extern "C" fn _post_return_get_workers(arg0: *mut u8,) { + $($path_to_types)*::__post_return_get_workers::<$ty>(arg0) + } + #[export_name = "golem:it/api#get-self-metadata"] + unsafe extern "C" fn export_get_self_metadata() -> *mut u8 { + $($path_to_types)*::_export_get_self_metadata_cabi::<$ty>() + } + #[export_name = "cabi_post_golem:it/api#get-self-metadata"] + unsafe extern "C" fn _post_return_get_self_metadata(arg0: *mut u8,) { + $($path_to_types)*::__post_return_get_self_metadata::<$ty>(arg0) + } + #[export_name = "golem:it/api#get-worker-metadata"] + unsafe extern "C" fn export_get_worker_metadata(arg0: i64,arg1: i64,arg2: *mut u8,arg3: usize,) -> *mut u8 { + $($path_to_types)*::_export_get_worker_metadata_cabi::<$ty>(arg0, arg1, arg2, arg3) + } + #[export_name = "cabi_post_golem:it/api#get-worker-metadata"] + unsafe extern "C" fn _post_return_get_worker_metadata(arg0: *mut u8,) { + $($path_to_types)*::__post_return_get_worker_metadata::<$ty>(arg0) + } + #[export_name = "golem:it/api#update-worker"] + unsafe extern "C" fn export_update_worker(arg0: i64,arg1: i64,arg2: *mut u8,arg3: usize,arg4: i64,arg5: i32,) { + $($path_to_types)*::_export_update_worker_cabi::<$ty>(arg0, arg1, arg2, arg3, arg4, arg5) + } + #[export_name = "golem:it/api#generate-idempotency-keys"] + unsafe extern "C" fn export_generate_idempotency_keys() -> *mut u8 { + $($path_to_types)*::_export_generate_idempotency_keys_cabi::<$ty>() + } + };); + } #[doc(hidden)] pub(crate) use __export_golem_it_api_cabi; #[repr(align(8))] @@ -12713,31 +12741,31 @@ mod _rt { #[doc(hidden)] macro_rules! __export_runtime_service_impl { - ($ty:ident) => (self::export!($ty with_types_in self);); - ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( - $($path_to_types_root)*::exports::golem::it::api::__export_golem_it_api_cabi!($ty with_types_in $($path_to_types_root)*::exports::golem::it::api); - ) - } + ($ty:ident) => (self::export!($ty with_types_in self);); + ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( + $($path_to_types_root)*::exports::golem::it::api::__export_golem_it_api_cabi!($ty with_types_in $($path_to_types_root)*::exports::golem::it::api); + ) + } #[doc(inline)] pub(crate) use __export_runtime_service_impl as export; #[cfg(target_arch = "wasm32")] #[link_section = "component-type:wit-bindgen:0.25.0:runtime-service:encoded world"] #[doc(hidden)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 10165] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xafN\x01A\x02\x01A\"\ -\x01B\x0a\x04\0\x08pollable\x03\x01\x01h\0\x01@\x01\x04self\x01\0\x7f\x04\0\x16[\ -method]pollable.ready\x01\x02\x01@\x01\x04self\x01\x01\0\x04\0\x16[method]pollab\ -le.block\x01\x03\x01p\x01\x01py\x01@\x01\x02in\x04\0\x05\x04\0\x04poll\x01\x06\x03\ -\x01\x12wasi:io/poll@0.2.0\x05\0\x02\x03\0\0\x08pollable\x01B*\x02\x03\x02\x01\x01\ -\x04\0\x08pollable\x03\0\0\x01z\x04\0\x0anode-index\x03\0\x02\x01r\x01\x05values\ -\x04\0\x03uri\x03\0\x04\x01p\x03\x01k\x03\x01o\x02y\x07\x01p\x7f\x01j\x01\x07\x01\ -\x07\x01o\x02\x05w\x01q\x16\x0crecord-value\x01\x06\0\x0dvariant-value\x01\x08\0\ -\x0aenum-value\x01y\0\x0bflags-value\x01\x09\0\x0btuple-value\x01\x06\0\x0alist-\ -value\x01\x06\0\x0coption-value\x01\x07\0\x0cresult-value\x01\x0a\0\x07prim-u8\x01\ -}\0\x08prim-u16\x01{\0\x08prim-u32\x01y\0\x08prim-u64\x01w\0\x07prim-s8\x01~\0\x08\ -prim-s16\x01|\0\x08prim-s32\x01z\0\x08prim-s64\x01x\0\x0cprim-float32\x01v\0\x0c\ -prim-float64\x01u\0\x09prim-char\x01t\0\x09prim-bool\x01\x7f\0\x0bprim-string\x01\ +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 10229] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xefN\x01A\x02\x01A#\x01\ +B\x0a\x04\0\x08pollable\x03\x01\x01h\0\x01@\x01\x04self\x01\0\x7f\x04\0\x16[meth\ +od]pollable.ready\x01\x02\x01@\x01\x04self\x01\x01\0\x04\0\x16[method]pollable.b\ +lock\x01\x03\x01p\x01\x01py\x01@\x01\x02in\x04\0\x05\x04\0\x04poll\x01\x06\x03\x01\ +\x12wasi:io/poll@0.2.0\x05\0\x02\x03\0\0\x08pollable\x01B*\x02\x03\x02\x01\x01\x04\ +\0\x08pollable\x03\0\0\x01z\x04\0\x0anode-index\x03\0\x02\x01r\x01\x05values\x04\ +\0\x03uri\x03\0\x04\x01p\x03\x01k\x03\x01o\x02y\x07\x01p\x7f\x01j\x01\x07\x01\x07\ +\x01o\x02\x05w\x01q\x16\x0crecord-value\x01\x06\0\x0dvariant-value\x01\x08\0\x0a\ +enum-value\x01y\0\x0bflags-value\x01\x09\0\x0btuple-value\x01\x06\0\x0alist-valu\ +e\x01\x06\0\x0coption-value\x01\x07\0\x0cresult-value\x01\x0a\0\x07prim-u8\x01}\0\ +\x08prim-u16\x01{\0\x08prim-u32\x01y\0\x08prim-u64\x01w\0\x07prim-s8\x01~\0\x08p\ +rim-s16\x01|\0\x08prim-s32\x01z\0\x08prim-s64\x01x\0\x0cprim-float32\x01v\0\x0cp\ +rim-float64\x01u\0\x09prim-char\x01t\0\x09prim-bool\x01\x7f\0\x0bprim-string\x01\ s\0\x06handle\x01\x0b\0\x04\0\x08wit-node\x03\0\x0c\x01p\x0d\x01r\x01\x05nodes\x0e\ \x04\0\x09wit-value\x03\0\x0f\x01q\x04\x0eprotocol-error\x01s\0\x06denied\x01s\0\ \x09not-found\x01s\0\x15remote-internal-error\x01s\0\x04\0\x09rpc-error\x03\0\x11\ @@ -12914,23 +12942,25 @@ error-code\x03\0\x06\x01i\x01\x01i\x03\x01k\x09\x01i\x05\x01j\x01\x0b\x01\x07\x0 @\x02\x07request\x08\x07options\x0a\0\x0c\x04\0\x06handle\x01\x0d\x03\x01\x20was\ i:http/outgoing-handler@0.2.0\x05\x11\x02\x03\0\x03\x0ccomponent-id\x02\x03\0\x03\ \x09worker-id\x02\x03\0\x03\x11component-version\x02\x03\0\x03\x0bupdate-mode\x02\ -\x03\0\x03\x11worker-any-filter\x02\x03\0\x03\x0fworker-metadata\x01B$\x02\x03\x02\ -\x01\x12\x04\0\x0ccomponent-id\x03\0\0\x02\x03\x02\x01\x13\x04\0\x09worker-id\x03\ -\0\x02\x02\x03\x02\x01\x14\x04\0\x11component-version\x03\0\x04\x02\x03\x02\x01\x15\ -\x04\0\x0bupdate-mode\x03\0\x06\x02\x03\x02\x01\x16\x04\0\x11worker-any-filter\x03\ -\0\x08\x02\x03\x02\x01\x17\x04\0\x0fworker-metadata\x03\0\x0a\x01@\x01\x0dfuncti\ -on-names\0s\x04\0\x0cget-self-uri\x01\x0c\x01@\0\0w\x04\0\x04jump\x01\x0d\x01@\x01\ -\x0bmax-retriesw\x01\0\x04\0\x1cfail-with-custom-max-retries\x01\x0e\x01@\x01\x08\ -replicas}\x01\0\x04\0\x0fexplicit-commit\x01\x0f\x01@\0\x01\0\x04\0\x0datomic-re\ -gion\x01\x10\x01@\x01\x07enabled\x7f\x01\0\x04\0\x10idempotence-flag\x01\x11\x04\ -\0\x0fpersist-nothing\x01\x10\x01k\x09\x01p\x0b\x01@\x03\x0ccomponent-id\x01\x06\ -filter\x12\x07precise\x7f\0\x13\x04\0\x0bget-workers\x01\x14\x01@\0\0\x0b\x04\0\x11\ -get-self-metadata\x01\x15\x01k\x0b\x01@\x01\x09worker-id\x03\0\x16\x04\0\x13get-\ -worker-metadata\x01\x17\x01@\x03\x09worker-id\x03\x11component-version\x05\x0bup\ -date-mode\x07\x01\0\x04\0\x0dupdate-worker\x01\x18\x04\x01\x0cgolem:it/api\x05\x18\ -\x04\x01\x18golem:it/runtime-service\x04\0\x0b\x15\x01\0\x0fruntime-service\x03\0\ -\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.208.1\x10wit-bi\ -ndgen-rust\x060.25.0"; +\x03\0\x03\x11worker-any-filter\x02\x03\0\x03\x0fworker-metadata\x02\x03\0\x03\x04\ +uuid\x01B)\x02\x03\x02\x01\x12\x04\0\x0ccomponent-id\x03\0\0\x02\x03\x02\x01\x13\ +\x04\0\x09worker-id\x03\0\x02\x02\x03\x02\x01\x14\x04\0\x11component-version\x03\ +\0\x04\x02\x03\x02\x01\x15\x04\0\x0bupdate-mode\x03\0\x06\x02\x03\x02\x01\x16\x04\ +\0\x11worker-any-filter\x03\0\x08\x02\x03\x02\x01\x17\x04\0\x0fworker-metadata\x03\ +\0\x0a\x02\x03\x02\x01\x18\x04\0\x04uuid\x03\0\x0c\x01@\x01\x0dfunction-names\0s\ +\x04\0\x0cget-self-uri\x01\x0e\x01@\0\0w\x04\0\x04jump\x01\x0f\x01@\x01\x0bmax-r\ +etriesw\x01\0\x04\0\x1cfail-with-custom-max-retries\x01\x10\x01@\x01\x08replicas\ +}\x01\0\x04\0\x0fexplicit-commit\x01\x11\x01@\0\x01\0\x04\0\x0datomic-region\x01\ +\x12\x01@\x01\x07enabled\x7f\x01\0\x04\0\x10idempotence-flag\x01\x13\x04\0\x0fpe\ +rsist-nothing\x01\x12\x01k\x09\x01p\x0b\x01@\x03\x0ccomponent-id\x01\x06filter\x14\ +\x07precise\x7f\0\x15\x04\0\x0bget-workers\x01\x16\x01@\0\0\x0b\x04\0\x11get-sel\ +f-metadata\x01\x17\x01k\x0b\x01@\x01\x09worker-id\x03\0\x18\x04\0\x13get-worker-\ +metadata\x01\x19\x01@\x03\x09worker-id\x03\x11component-version\x05\x0bupdate-mo\ +de\x07\x01\0\x04\0\x0dupdate-worker\x01\x1a\x01o\x02\x0d\x0d\x01@\0\0\x1b\x04\0\x19\ +generate-idempotency-keys\x01\x1c\x04\x01\x0cgolem:it/api\x05\x19\x04\x01\x18gol\ +em:it/runtime-service\x04\0\x0b\x15\x01\0\x0fruntime-service\x03\0\0\0G\x09produ\ +cers\x01\x0cprocessed-by\x02\x0dwit-component\x070.208.1\x10wit-bindgen-rust\x06\ +0.25.0"; #[inline(never)] #[doc(hidden)] diff --git a/test-components/runtime-service/src/lib.rs b/test-components/runtime-service/src/lib.rs index b6956ba8d9..aa0cd99c7b 100644 --- a/test-components/runtime-service/src/lib.rs +++ b/test-components/runtime-service/src/lib.rs @@ -194,6 +194,12 @@ impl Guest for Component { ); bindings::golem::api::host::update_worker(&worker_id, component_version, update_mode); } + + fn generate_idempotency_keys() -> (bindings::exports::golem::it::api::Uuid, bindings::exports::golem::it::api::Uuid) { + let key1 = generate_idempotency_key(); + let key2 = generate_idempotency_key(); + (key1, key2) + } } fn remote_call(param: u64) -> bool { diff --git a/test-components/runtime-service/wit/runtime.wit b/test-components/runtime-service/wit/runtime.wit index da18e7460a..93b929cd10 100644 --- a/test-components/runtime-service/wit/runtime.wit +++ b/test-components/runtime-service/wit/runtime.wit @@ -7,8 +7,11 @@ interface api { component-version, update-mode, worker-any-filter, - worker-metadata + worker-metadata, + uuid }; + + get-self-uri: func(function-name: string) -> string; jump: func() -> u64; fail-with-custom-max-retries: func(max-retries: u64) -> (); @@ -20,6 +23,8 @@ interface api { get-self-metadata: func() -> worker-metadata; get-worker-metadata: func(worker-id: worker-id) -> option; update-worker: func(worker-id: worker-id, component-version: component-version, update-mode: update-mode) -> (); + + generate-idempotency-keys: func() -> tuple; } world runtime-service { diff --git a/test-components/shopping-cart-resource.wasm b/test-components/shopping-cart-resource.wasm index 7956427645..aa8c4d418f 100755 Binary files a/test-components/shopping-cart-resource.wasm and b/test-components/shopping-cart-resource.wasm differ diff --git a/test-components/shopping-cart.wasm b/test-components/shopping-cart.wasm index 1555edb50b..1a5737bda5 100644 Binary files a/test-components/shopping-cart.wasm and b/test-components/shopping-cart.wasm differ diff --git a/test-components/stdio-cc.wasm b/test-components/stdio-cc.wasm index bfceba6547..46456f2a43 100755 Binary files a/test-components/stdio-cc.wasm and b/test-components/stdio-cc.wasm differ diff --git a/test-components/update-test-v1.wasm b/test-components/update-test-v1.wasm index cd70c59d5a..2ab4a974c8 100755 Binary files a/test-components/update-test-v1.wasm and b/test-components/update-test-v1.wasm differ diff --git a/test-components/update-test-v2.wasm b/test-components/update-test-v2.wasm index fb7be478e9..fe1c78336e 100755 Binary files a/test-components/update-test-v2.wasm and b/test-components/update-test-v2.wasm differ diff --git a/test-components/update-test-v3.wasm b/test-components/update-test-v3.wasm index fb9e8dc4b0..1264b0603b 100755 Binary files a/test-components/update-test-v3.wasm and b/test-components/update-test-v3.wasm differ diff --git a/test-components/update-test-v4.wasm b/test-components/update-test-v4.wasm index c92e3f2375..857eb8835e 100755 Binary files a/test-components/update-test-v4.wasm and b/test-components/update-test-v4.wasm differ diff --git a/test-components/write-stderr.wasm b/test-components/write-stderr.wasm index c901db92cb..f38e830db1 100755 Binary files a/test-components/write-stderr.wasm and b/test-components/write-stderr.wasm differ diff --git a/test-components/write-stdout.wasm b/test-components/write-stdout.wasm index 0e2ad5d4ff..8925105990 100644 Binary files a/test-components/write-stdout.wasm and b/test-components/write-stdout.wasm differ