diff --git a/.github/workflows/net-ci.yml b/.github/workflows/net-ci.yml
index e698b6d1..d5386740 100644
--- a/.github/workflows/net-ci.yml
+++ b/.github/workflows/net-ci.yml
@@ -19,6 +19,8 @@ jobs:
build_test:
name: Build & Test
runs-on: ubuntu-latest
+ permissions:
+ packages: read
defaults:
run:
shell: bash
@@ -33,7 +35,14 @@ jobs:
dotnet-version: 8.0.x
- name: Restore Solution
- run: >-
+ run: |
+ NUGET_SOURCE_URL="https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json"
+ dotnet nuget remove source ${{ github.repository_owner }}-github || true
+ dotnet nuget add source $NUGET_SOURCE_URL \
+ --name ${{ github.repository_owner }}-github \
+ --username "${{ github.workflow }}" \
+ --password ${{ secrets.GITHUB_TOKEN }} \
+ --store-password-in-clear-text
dotnet restore
- name: Build Solution
diff --git a/Sails.Net.sln b/Sails.Net.sln
index ba363611..7cf30a1d 100644
--- a/Sails.Net.sln
+++ b/Sails.Net.sln
@@ -33,6 +33,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Substrate.Gear.Client.Tests
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sails.Client.Tests", "net\tests\Sails.Client.Tests\Sails.Client.Tests.csproj", "{BC248D44-14CD-4BB0-9AF9-4E0750574492}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{4D457454-ED79-4BC3-8B6B-AC6934AAF048}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sails.DemoClient", "net\examples\Sails.DemoClient\Sails.DemoClient.csproj", "{C9D87AD3-612B-43A0-89BD-9211FE2FB310}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sails.DemoClient.Tests", "net\tests\Sails.DemoClient.Tests\Sails.DemoClient.Tests.csproj", "{5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -83,6 +89,14 @@ Global
{BC248D44-14CD-4BB0-9AF9-4E0750574492}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC248D44-14CD-4BB0-9AF9-4E0750574492}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC248D44-14CD-4BB0-9AF9-4E0750574492}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C9D87AD3-612B-43A0-89BD-9211FE2FB310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C9D87AD3-612B-43A0-89BD-9211FE2FB310}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C9D87AD3-612B-43A0-89BD-9211FE2FB310}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C9D87AD3-612B-43A0-89BD-9211FE2FB310}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -93,6 +107,8 @@ Global
{A6A2172B-8F8F-4BDC-B519-E7299FFCCA5F} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F}
{42B621CE-C2B4-4911-961C-5B087A514AF5} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F}
{BC248D44-14CD-4BB0-9AF9-4E0750574492} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F}
+ {C9D87AD3-612B-43A0-89BD-9211FE2FB310} = {4D457454-ED79-4BC3-8B6B-AC6934AAF048}
+ {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0894C08B-8BB9-401D-8471-26F5EB5A4EA2}
diff --git a/net/Directory.Packages.props b/net/Directory.Packages.props
index 17b57a68..c5b61101 100644
--- a/net/Directory.Packages.props
+++ b/net/Directory.Packages.props
@@ -11,7 +11,7 @@
-
+
@@ -19,17 +19,21 @@
+
-
+
-
+
+
+
+
diff --git a/net/examples/Sails.DemoClient/Sails.DemoClient.csproj b/net/examples/Sails.DemoClient/Sails.DemoClient.csproj
new file mode 100644
index 00000000..3e49ccb2
--- /dev/null
+++ b/net/examples/Sails.DemoClient/Sails.DemoClient.csproj
@@ -0,0 +1,16 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/net/examples/Sails.DemoClient/demo.idl b/net/examples/Sails.DemoClient/demo.idl
new file mode 100644
index 00000000..d7cc6728
--- /dev/null
+++ b/net/examples/Sails.DemoClient/demo.idl
@@ -0,0 +1,91 @@
+type ReferenceCount = struct {
+ u32,
+};
+
+type DoThatParam = struct {
+ p1: nat32,
+ p2: actor_id,
+ p3: ManyVariants,
+};
+
+type ManyVariants = enum {
+ One,
+ Two: u32,
+ Three: opt u256,
+ Four: struct { a: u32, b: opt u16 },
+ Five: struct { str, h256 },
+ Six: struct { u32 },
+};
+
+type TupleStruct = struct {
+ bool,
+};
+
+constructor {
+ /// Program constructor (called once at the very beginning of the program lifetime)
+ Default : ();
+ /// Another program constructor (called once at the very beginning of the program lifetime)
+ New : (counter: opt u32, dog_position: opt struct { i32, i32 });
+};
+
+service Counter {
+ /// Add a value to the counter
+ Add : (value: u32) -> u32;
+ /// Substract a value from the counter
+ Sub : (value: u32) -> u32;
+ /// Get the current value
+ query Value : () -> u32;
+
+ events {
+ /// Emitted when a new value is added to the counter
+ Added: u32;
+ /// Emitted when a value is subtracted from the counter
+ Subtracted: u32;
+ }
+};
+
+service Dog {
+ MakeSound : () -> str;
+ Walk : (dx: i32, dy: i32) -> null;
+ query AvgWeight : () -> u32;
+ query Position : () -> struct { i32, i32 };
+
+ events {
+ Barked;
+ Walked: struct { from: struct { i32, i32 }, to: struct { i32, i32 } };
+ }
+};
+
+service PingPong {
+ Ping : (input: str) -> result (str, str);
+};
+
+service References {
+ Add : (v: u32) -> u32;
+ AddByte : (byte: u8) -> vec u8;
+ GuessNum : (number: u8) -> result (str, str);
+ Incr : () -> ReferenceCount;
+ SetNum : (number: u8) -> result (null, str);
+ query Baked : () -> str;
+ query LastByte : () -> opt u8;
+ query Message : () -> opt str;
+};
+
+service ThisThat {
+ DoThat : (param: DoThatParam) -> result (struct { actor_id, nat32 }, struct { str });
+ DoThis : (p1: u32, p2: str, p3: struct { opt h160, nat8 }, p4: TupleStruct) -> struct { str, u32 };
+ Noop : () -> null;
+ query That : () -> result (str, str);
+ query This : () -> u32;
+};
+
+service ValueFee {
+ /// Return flag if fee taken and remain value,
+ /// using special type `CommandReply`
+ DoSomethingAndTakeFee : () -> bool;
+
+ events {
+ Withheld: u128;
+ }
+};
+
diff --git a/net/rs/client-gen/src/ctor_generators.rs b/net/rs/client-gen/src/ctor_generators.rs
index 690f1d84..27feaf11 100644
--- a/net/rs/client-gen/src/ctor_generators.rs
+++ b/net/rs/client-gen/src/ctor_generators.rs
@@ -1,7 +1,4 @@
-use crate::{
- helpers::*,
- type_generators::{primitive_type_to_dotnet, TypeDeclGenerator},
-};
+use crate::{helpers::*, type_decl_generators::*};
use convert_case::{Case, Casing};
use csharp::Tokens;
use genco::prelude::*;
@@ -63,19 +60,9 @@ impl<'a> Visitor<'a> for CtorFactoryGenerator<'a> {
self.interface_tokens.push();
let route_bytes = &path_bytes(func.name()).0;
- let args = &encoded_fn_args(func.params());
+ let args = &encoded_fn_args_comma_prefixed(func.params());
let args_with_type = &self.type_generator.fn_params_with_types(func.params());
-
- let type_decls = func
- .params()
- .iter()
- .map(|p| p.type_decl())
- .collect::>();
- let tuple_arg_type = if type_decls.is_empty() {
- primitive_type_to_dotnet(PrimitiveType::Null).to_string()
- } else {
- self.type_generator.generate_types_as_tuple(type_decls)
- };
+ let void_type = primitive_type_to_dotnet(PrimitiveType::Null);
let activation = &csharp::import("global::Sails.Remoting.Abstractions", "IActivation");
let action = &csharp::import("global::Sails.Remoting", "RemotingAction");
@@ -88,10 +75,7 @@ impl<'a> Visitor<'a> for CtorFactoryGenerator<'a> {
$(inheritdoc())
public $activation $func_name_pascal($args_with_type)
{
- return new $action<$(&tuple_arg_type)>(
- this.remoting,
- [$route_bytes],
- new $(&tuple_arg_type)($args));
+ return new $action<$(void_type)>(this.remoting, [$route_bytes]$args);
}
$['\n']
};
diff --git a/net/rs/client-gen/src/events_generator.rs b/net/rs/client-gen/src/events_generator.rs
index 7b7bad38..c8fd1180 100644
--- a/net/rs/client-gen/src/events_generator.rs
+++ b/net/rs/client-gen/src/events_generator.rs
@@ -1,5 +1,4 @@
-use crate::helpers::*;
-use crate::type_generators::{primitive_type_to_dotnet, TypeDeclGenerator};
+use crate::{helpers::*, type_decl_generators::*};
use convert_case::{Case, Casing};
use csharp::Tokens;
use genco::prelude::*;
diff --git a/net/rs/client-gen/src/helpers.rs b/net/rs/client-gen/src/helpers.rs
index 3f5f0bcf..0ccdb60c 100644
--- a/net/rs/client-gen/src/helpers.rs
+++ b/net/rs/client-gen/src/helpers.rs
@@ -22,12 +22,17 @@ pub(crate) fn path_bytes(path: &str) -> (String, usize) {
}
}
-pub(crate) fn encoded_fn_args(params: &[FuncParam]) -> String {
+pub(crate) fn encoded_fn_args_comma_prefixed(params: &[FuncParam]) -> String {
params
.iter()
- .map(|p| escape_keywords(p.name().to_case(convert_case::Case::Camel)))
+ .map(|p| {
+ format!(
+ ", {}",
+ escape_keywords(p.name().to_case(convert_case::Case::Camel))
+ )
+ })
.collect::>()
- .join(", ")
+ .join("")
}
pub fn summary_comment(comment: T) -> SummaryComment
diff --git a/net/rs/client-gen/src/lib.rs b/net/rs/client-gen/src/lib.rs
index 27d5a49b..bc1549e4 100644
--- a/net/rs/client-gen/src/lib.rs
+++ b/net/rs/client-gen/src/lib.rs
@@ -10,7 +10,8 @@ mod events_generator;
mod helpers;
mod root_generator;
mod service_generators;
-mod type_generators;
+mod tol_level_type_generators;
+mod type_decl_generators;
pub struct IdlPath<'a>(&'a Path);
@@ -69,7 +70,8 @@ impl<'a> ClientGenerator<'a, IdlString<'a>> {
RootGenerator::new(anonymous_service_name, namespace, self.external_types);
visitor::accept_program(&program, &mut generator);
let tokens = generator.finalize();
- let code = tokens.to_file_string()?;
+ let mut code = "// \n".to_owned();
+ code.push_str(&tokens.to_file_string()?);
Ok(code)
}
diff --git a/net/rs/client-gen/src/root_generator.rs b/net/rs/client-gen/src/root_generator.rs
index f0a4dc7d..cc109075 100644
--- a/net/rs/client-gen/src/root_generator.rs
+++ b/net/rs/client-gen/src/root_generator.rs
@@ -1,4 +1,7 @@
-use crate::{ctor_generators::*, events_generator::*, service_generators::*, type_generators::*};
+use crate::{
+ ctor_generators::*, events_generator::*, service_generators::*, tol_level_type_generators::*,
+ type_decl_generators::*,
+};
use convert_case::{Case, Casing};
use csharp::Tokens;
use genco::{prelude::*, tokens::ItemStr};
@@ -19,6 +22,8 @@ impl<'a> RootGenerator<'a> {
external_types: HashMap<&'a str, &'a str>,
) -> Self {
let mut tokens = Tokens::new();
+ tokens.append(ItemStr::Static("#nullable enable"));
+ tokens.line();
tokens.append(ItemStr::Static(
"#pragma warning disable RCS0056 // A line is too long",
));
diff --git a/net/rs/client-gen/src/service_generators.rs b/net/rs/client-gen/src/service_generators.rs
index fac502ae..9adaeee9 100644
--- a/net/rs/client-gen/src/service_generators.rs
+++ b/net/rs/client-gen/src/service_generators.rs
@@ -1,11 +1,9 @@
-use crate::{helpers::*, type_generators::TypeDeclGenerator};
+use crate::{helpers::*, type_decl_generators::*};
use convert_case::{Case, Casing};
use csharp::Tokens;
use genco::prelude::*;
use sails_idl_parser::{ast::visitor, ast::visitor::Visitor, ast::*};
-const BASE_TUPLE_RUST: &str = "global::Substrate.NetApi.Model.Types.Base.BaseTupleRust";
-
/// Generates a client that implements service trait
pub(crate) struct ServiceClientGenerator<'a> {
service_name: String,
@@ -63,7 +61,7 @@ impl<'a> Visitor<'a> for ServiceClientGenerator<'a> {
let func_route_bytes = path_bytes(func.name()).0;
let route_bytes = [service_route_bytes, func_route_bytes].join(", ");
- let args = encoded_fn_args(func.params());
+ let args = &encoded_fn_args_comma_prefixed(func.params());
let args_with_type = &self.type_generator.fn_params_with_types(func.params());
let func_return_type = &self.type_generator.generate_type_decl(func.output());
@@ -80,11 +78,7 @@ impl<'a> Visitor<'a> for ServiceClientGenerator<'a> {
$(inheritdoc())
public $return_type<$func_return_type> $func_name_pascal($args_with_type)
{
- return new $action<$func_return_type>(
- this.remoting,
- [$(&route_bytes)],
- new $(BASE_TUPLE_RUST)($(&args))
- );
+ return new $action<$func_return_type>(this.remoting, [$(&route_bytes)]$args);
}
};
}
diff --git a/net/rs/client-gen/src/tol_level_type_generators.rs b/net/rs/client-gen/src/tol_level_type_generators.rs
new file mode 100644
index 00000000..3901796a
--- /dev/null
+++ b/net/rs/client-gen/src/tol_level_type_generators.rs
@@ -0,0 +1,218 @@
+use crate::{
+ helpers::*,
+ type_decl_generators::{primitive_type_to_dotnet, TypeDeclGenerator},
+};
+use convert_case::{Case, Casing};
+use csharp::Tokens;
+use genco::prelude::*;
+use sails_idl_parser::{ast::visitor, ast::visitor::Visitor, ast::*};
+
+pub(crate) struct TopLevelTypeGenerator<'a> {
+ type_name: &'a str,
+ type_generator: TypeDeclGenerator<'a>,
+ tokens: Tokens,
+}
+
+impl<'a> TopLevelTypeGenerator<'a> {
+ pub(crate) fn new(type_name: &'a str, type_generator: TypeDeclGenerator<'a>) -> Self {
+ Self {
+ type_name,
+ type_generator,
+ tokens: Tokens::new(),
+ }
+ }
+
+ pub(crate) fn finalize(self) -> Tokens {
+ self.tokens
+ }
+}
+
+impl<'a> Visitor<'a> for TopLevelTypeGenerator<'a> {
+ fn visit_type(&mut self, type_: &'a Type) {
+ self.tokens.push();
+ self.tokens.append(summary_comment(type_.docs()));
+ self.tokens.push();
+ visitor::accept_type(type_, self);
+ self.tokens.line();
+ }
+
+ fn visit_struct_def(&mut self, struct_def: &'a StructDef) {
+ let mut struct_def_generator =
+ StructDefGenerator::new(self.type_name, self.type_generator.clone());
+ struct_def_generator.visit_struct_def(struct_def);
+ self.tokens.extend(struct_def_generator.finalize());
+ }
+
+ fn visit_enum_def(&mut self, enum_def: &'a EnumDef) {
+ let mut enum_def_generator =
+ EnumDefGenerator::new(self.type_name, self.type_generator.clone());
+ enum_def_generator.visit_enum_def(enum_def);
+ self.tokens.extend(enum_def_generator.finalize());
+ }
+}
+
+struct StructDefGenerator<'a> {
+ type_name: &'a str,
+ type_generator: TypeDeclGenerator<'a>,
+ is_tuple_struct: bool,
+ props_tokens: Tokens,
+ encode_tokens: Tokens,
+ decode_tokens: Tokens,
+}
+
+impl<'a> StructDefGenerator<'a> {
+ fn new(type_name: &'a str, type_generator: TypeDeclGenerator<'a>) -> Self {
+ Self {
+ type_name,
+ type_generator,
+ is_tuple_struct: false,
+ props_tokens: Tokens::new(),
+ encode_tokens: Tokens::new(),
+ decode_tokens: Tokens::new(),
+ }
+ }
+
+ pub(crate) fn finalize(self) -> Tokens {
+ let system_array = &csharp::import("global::System", "Array");
+ let generic_list = &csharp::import("global::System.Collections.Generic", "List");
+
+ quote! {
+ public sealed partial class $(self.type_name) : global::Substrate.NetApi.Model.Types.Base.BaseType
+ {
+ $(self.props_tokens)
+
+ $(inheritdoc())
+ public override string TypeName() => $(quoted(self.type_name));
+
+ $(inheritdoc())
+ public override byte[] Encode()
+ {
+ var result = new $generic_list();$['\r']
+ $(self.encode_tokens)
+ return result.ToArray();$['\r']
+ }
+
+ $(inheritdoc())
+ public override void Decode(byte[] byteArray, ref int p)
+ {
+ var start = p;$['\r']
+ $(self.decode_tokens)
+ var bytesLength = p - start;
+ this.TypeSize = bytesLength;
+ this.Bytes = new byte[bytesLength];
+ $system_array.Copy(byteArray, start, this.Bytes, 0, bytesLength);
+ }
+ }
+ }
+ }
+
+ fn tuple_struct(&mut self, struct_def: &'a StructDef) {
+ if struct_def.fields().is_empty() {
+ return;
+ }
+ let value_type = &self.type_generator.generate_struct_def(struct_def);
+ quote_in! { self.props_tokens =>
+ public $value_type Value { get; init; } = new();$['\r']
+ };
+ quote_in! { self.encode_tokens =>
+ result.AddRange(this.Value.Encode());$['\r']
+ };
+ quote_in! { self.decode_tokens =>
+ this.Value.Decode(byteArray, ref p);$['\r']
+ };
+ }
+}
+
+impl<'a> Visitor<'a> for StructDefGenerator<'a> {
+ fn visit_struct_def(&mut self, struct_def: &'a StructDef) {
+ let is_regular_struct = struct_def.fields().iter().all(|f| f.name().is_some());
+ let is_tuple_struct = struct_def.fields().iter().all(|f| f.name().is_none());
+ if !is_regular_struct && !is_tuple_struct {
+ panic!("Struct must be either regular or tuple");
+ }
+ self.is_tuple_struct = is_tuple_struct;
+
+ if is_tuple_struct {
+ self.tuple_struct(struct_def);
+ } else {
+ visitor::accept_struct_def(struct_def, self);
+ }
+ }
+
+ fn visit_struct_field(&mut self, struct_field: &'a StructField) {
+ let type_decl_code = &self
+ .type_generator
+ .generate_type_decl(struct_field.type_decl());
+
+ self.props_tokens.push();
+ self.props_tokens
+ .append(summary_comment(struct_field.docs()));
+ self.props_tokens.push();
+ if let Some(field_name) = struct_field.name() {
+ let field_name_pascal = &field_name.to_case(Case::Pascal);
+ quote_in! { self.props_tokens =>
+ public $type_decl_code $field_name_pascal { get; init; } = new();$['\r']
+ };
+ quote_in! { self.encode_tokens =>
+ result.AddRange(this.$field_name_pascal.Encode());$['\r']
+ };
+ quote_in! { self.decode_tokens =>
+ this.$field_name_pascal.Decode(byteArray, ref p);$['\r']
+ };
+ }
+ }
+}
+
+struct EnumDefGenerator<'a> {
+ type_name: &'a str,
+ type_generator: TypeDeclGenerator<'a>,
+ enum_tokens: Tokens,
+ class_tokens: Tokens,
+}
+
+impl<'a> EnumDefGenerator<'a> {
+ pub(crate) fn new(type_name: &'a str, type_generator: TypeDeclGenerator<'a>) -> Self {
+ Self {
+ type_name,
+ type_generator,
+ enum_tokens: Tokens::new(),
+ class_tokens: Tokens::new(),
+ }
+ }
+
+ pub(crate) fn finalize(self) -> Tokens {
+ let class_name = &format!("Enum{}", self.type_name);
+ quote!(
+ public enum $(self.type_name)
+ {
+ $(self.enum_tokens)
+ }
+
+ public sealed partial class $class_name : global::Substrate.NetApi.Model.Types.Base.BaseEnumRust<$(self.type_name)>
+ {
+ public $class_name()
+ {
+ $(self.class_tokens)
+ }
+ }
+ )
+ }
+}
+
+impl<'ast> Visitor<'ast> for EnumDefGenerator<'ast> {
+ fn visit_enum_variant(&mut self, enum_variant: &'ast EnumVariant) {
+ quote_in! { self.enum_tokens =>
+ $(summary_comment(enum_variant.docs()))
+ $(enum_variant.name()),$['\r']
+ };
+
+ let type_decl_code = if let Some(type_decl) = enum_variant.type_decl().as_ref() {
+ self.type_generator.generate_type_decl(type_decl)
+ } else {
+ primitive_type_to_dotnet(PrimitiveType::Null).into()
+ };
+ quote_in! { self.class_tokens =>
+ this.AddTypeDecoder<$(type_decl_code)>($(self.type_name).$(enum_variant.name()));$['\r']
+ }
+ }
+}
diff --git a/net/rs/client-gen/src/type_decl_generators.rs b/net/rs/client-gen/src/type_decl_generators.rs
new file mode 100644
index 00000000..a238ef47
--- /dev/null
+++ b/net/rs/client-gen/src/type_decl_generators.rs
@@ -0,0 +1,193 @@
+use crate::helpers::*;
+use convert_case::Casing;
+use sails_idl_parser::{ast::visitor, ast::visitor::Visitor, ast::*};
+
+macro_rules! base {
+ ($t: expr) => {
+ concat!("global::Substrate.NetApi.Model.Types.Base.", $t)
+ };
+}
+
+macro_rules! primitive {
+ ($t: expr) => {
+ concat!("global::Substrate.NetApi.Model.Types.Primitive.", $t)
+ };
+}
+
+macro_rules! gprimitives {
+ ($t: expr) => {
+ concat!(
+ "global::Substrate.Gear.Api.Generated.Model.gprimitives.",
+ $t
+ )
+ };
+}
+
+macro_rules! client_base {
+ ($t: expr) => {
+ concat!("global::Substrate.Gear.Client.NetApi.Model.Types.Base.", $t)
+ };
+}
+
+macro_rules! client_primitive {
+ ($t: expr) => {
+ concat!(
+ "global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.",
+ $t
+ )
+ };
+}
+
+#[derive(Clone)]
+pub(crate) struct TypeDeclGenerator<'a> {
+ code: String,
+ generated_types: &'a Vec<&'a Type>,
+}
+
+impl<'a> TypeDeclGenerator<'a> {
+ pub(crate) fn new(generated_types: &'a Vec<&'a Type>) -> Self {
+ Self {
+ code: String::new(),
+ generated_types,
+ }
+ }
+
+ pub(crate) fn generate_type_decl(&mut self, type_decl: &'a TypeDecl) -> String {
+ visitor::accept_type_decl(type_decl, self);
+ std::mem::take(&mut self.code)
+ }
+
+ pub(crate) fn generate_struct_def(&mut self, struct_def: &'a StructDef) -> String {
+ visitor::accept_struct_def(struct_def, self);
+ std::mem::take(&mut self.code)
+ }
+
+ fn join_type_decls>(
+ &mut self,
+ type_decls: I,
+ separator: &str,
+ ) {
+ let prev_code = std::mem::take(&mut self.code);
+ let mut type_decls_str: Vec = Vec::new();
+ let iter = type_decls.into_iter();
+ for type_decl in iter {
+ visitor::accept_type_decl(type_decl, self);
+ type_decls_str.push(std::mem::take(&mut self.code));
+ }
+ _ = std::mem::replace(&mut self.code, prev_code);
+ self.code.push_str(type_decls_str.join(separator).as_str());
+ }
+
+ pub(crate) fn fn_params_with_types(&mut self, params: &'a [FuncParam]) -> String {
+ params
+ .iter()
+ .map(|p| {
+ format!(
+ "{} {}",
+ self.generate_type_decl(p.type_decl()),
+ escape_keywords(p.name().to_case(convert_case::Case::Camel))
+ )
+ })
+ .collect::>()
+ .join(", ")
+ }
+}
+
+impl<'a> Visitor<'a> for TypeDeclGenerator<'a> {
+ fn visit_optional_type_decl(&mut self, optional_type_decl: &'a TypeDecl) {
+ self.code.push_str(base!("BaseOpt<"));
+ visitor::accept_type_decl(optional_type_decl, self);
+ self.code.push('>');
+ }
+
+ fn visit_result_type_decl(&mut self, ok_type_decl: &'a TypeDecl, err_type_decl: &'a TypeDecl) {
+ self.code.push_str(client_base!("BaseResult<"));
+ visitor::accept_type_decl(ok_type_decl, self);
+ self.code.push_str(", ");
+ visitor::accept_type_decl(err_type_decl, self);
+ self.code.push('>');
+ }
+
+ fn visit_vector_type_decl(&mut self, vector_type_decl: &'a TypeDecl) {
+ self.code.push_str(base!("BaseVec<"));
+ visitor::accept_type_decl(vector_type_decl, self);
+ self.code.push('>');
+ }
+
+ fn visit_struct_def(&mut self, struct_def: &'a StructDef) {
+ if struct_def.fields().is_empty() {
+ return;
+ }
+ if struct_def.fields().len() == 1 {
+ visitor::accept_type_decl(struct_def.fields()[0].type_decl(), self);
+ } else {
+ self.code.push_str(base!("BaseTuple<"));
+ self.join_type_decls(struct_def.fields().iter().map(|f| f.type_decl()), ", ");
+ self.code.push('>');
+ }
+ }
+
+ fn visit_primitive_type_id(&mut self, primitive_type_id: PrimitiveType) {
+ self.code
+ .push_str(primitive_type_to_dotnet(primitive_type_id));
+ }
+
+ fn visit_user_defined_type_id(&mut self, user_defined_type_id: &'a str) {
+ let is_enum = self
+ .generated_types
+ .iter()
+ .find(|&&t| t.name() == user_defined_type_id)
+ .map(|&t| matches!(t.def(), TypeDef::Enum(_)))
+ .unwrap_or_default();
+ let type_id = if is_enum {
+ &format!("Enum{}", user_defined_type_id) // Enum prefix
+ } else {
+ user_defined_type_id
+ };
+ self.code.push_str(type_id);
+ }
+
+ fn visit_map_type_decl(&mut self, key_type_decl: &'a TypeDecl, value_type_decl: &'a TypeDecl) {
+ self.code.push_str(client_base!("BaseDictionary<"));
+ visitor::accept_type_decl(key_type_decl, self);
+ self.code.push_str(", ");
+ visitor::accept_type_decl(value_type_decl, self);
+ self.code.push('>');
+ }
+
+ fn visit_array_type_decl(&mut self, item_type_decl: &'a TypeDecl, _len: u32) {
+ visitor::accept_type_decl(item_type_decl, self);
+ self.code.push_str("[]");
+ }
+}
+
+pub(crate) fn primitive_type_to_dotnet(primitive_type: PrimitiveType) -> &'static str {
+ match primitive_type {
+ PrimitiveType::U8 => primitive!("U8"),
+ PrimitiveType::U16 => primitive!("U16"),
+ PrimitiveType::U32 => primitive!("U32"),
+ PrimitiveType::U64 => primitive!("U64"),
+ PrimitiveType::U128 => primitive!("U128"),
+ PrimitiveType::I8 => primitive!("I8"),
+ PrimitiveType::I16 => primitive!("I16"),
+ PrimitiveType::I32 => primitive!("I32"),
+ PrimitiveType::I64 => primitive!("I64"),
+ PrimitiveType::I128 => primitive!("I128"),
+ PrimitiveType::Bool => primitive!("Bool"),
+ PrimitiveType::Str => primitive!("Str"),
+ PrimitiveType::Char => primitive!("PrimChar"),
+ PrimitiveType::Null => base!("BaseVoid"),
+ PrimitiveType::ActorId => gprimitives!("ActorId"),
+ PrimitiveType::CodeId => gprimitives!("CodeId"),
+ PrimitiveType::MessageId => gprimitives!("MessageId"),
+ PrimitiveType::H160 => client_primitive!("H160"),
+ PrimitiveType::H256 => "global::Substrate.Gear.Api.Generated.Model.primitive_types.H256",
+ PrimitiveType::U256 => primitive!("U256"),
+ PrimitiveType::NonZeroU8 => client_primitive!("NonZeroU8"),
+ PrimitiveType::NonZeroU16 => client_primitive!("NonZeroU16"),
+ PrimitiveType::NonZeroU32 => "global::Substrate.Gear.Api.Generated.Types.Base.NonZeroU32",
+ PrimitiveType::NonZeroU64 => client_primitive!("NonZeroU64"),
+ PrimitiveType::NonZeroU128 => client_primitive!("NonZeroU128"),
+ PrimitiveType::NonZeroU256 => client_primitive!("NonZeroU256"),
+ }
+}
diff --git a/net/rs/client-gen/src/type_generators.rs b/net/rs/client-gen/src/type_generators.rs
deleted file mode 100644
index 027329b1..00000000
--- a/net/rs/client-gen/src/type_generators.rs
+++ /dev/null
@@ -1,418 +0,0 @@
-use crate::helpers::*;
-use convert_case::{Case, Casing};
-use csharp::Tokens;
-use genco::prelude::*;
-use sails_idl_parser::{ast::visitor, ast::visitor::Visitor, ast::*};
-
-macro_rules! base {
- ($t: expr) => {
- concat!("global::Substrate.NetApi.Model.Types.Base.", $t)
- };
-}
-
-macro_rules! primitive {
- ($t: expr) => {
- concat!("global::Substrate.NetApi.Model.Types.Primitive.", $t)
- };
-}
-
-macro_rules! gprimitives {
- ($t: expr) => {
- concat!(
- "global::Substrate.Gear.Api.Generated.Model.gprimitives.",
- $t
- )
- };
-}
-
-macro_rules! client_base {
- ($t: expr) => {
- concat!("global::Substrate.Gear.Client.NetApi.Model.Types.Base.", $t)
- };
-}
-
-macro_rules! client_primitive {
- ($t: expr) => {
- concat!("global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.", $t)
- };
-}
-
-pub(crate) struct TopLevelTypeGenerator<'a> {
- type_name: &'a str,
- type_generator: TypeDeclGenerator<'a>,
- tokens: Tokens,
-}
-
-impl<'a> TopLevelTypeGenerator<'a> {
- pub(crate) fn new(type_name: &'a str, type_generator: TypeDeclGenerator<'a>) -> Self {
- Self {
- type_name,
- type_generator,
- tokens: Tokens::new(),
- }
- }
-
- pub(crate) fn finalize(self) -> Tokens {
- self.tokens
- }
-}
-
-impl<'a> Visitor<'a> for TopLevelTypeGenerator<'a> {
- fn visit_type(&mut self, type_: &'a Type) {
- self.tokens.push();
- self.tokens.append(summary_comment(type_.docs()));
- self.tokens.push();
- visitor::accept_type(type_, self);
- self.tokens.line();
- }
-
- fn visit_struct_def(&mut self, struct_def: &'a StructDef) {
- let mut struct_def_generator =
- StructDefGenerator::new(self.type_name, self.type_generator.clone());
- struct_def_generator.visit_struct_def(struct_def);
- self.tokens.extend(struct_def_generator.finalize());
- }
-
- fn visit_enum_def(&mut self, enum_def: &'a EnumDef) {
- let mut enum_def_generator =
- EnumDefGenerator::new(self.type_name, self.type_generator.clone());
- enum_def_generator.visit_enum_def(enum_def);
- self.tokens.extend(enum_def_generator.finalize());
- }
-}
-
-struct StructDefGenerator<'a> {
- type_name: &'a str,
- type_generator: TypeDeclGenerator<'a>,
- is_tuple_struct: bool,
- props_tokens: Tokens,
- encode_tokens: Tokens,
- decode_tokens: Tokens,
-}
-
-impl<'a> StructDefGenerator<'a> {
- fn new(type_name: &'a str, type_generator: TypeDeclGenerator<'a>) -> Self {
- Self {
- type_name,
- type_generator,
- is_tuple_struct: false,
- props_tokens: Tokens::new(),
- encode_tokens: Tokens::new(),
- decode_tokens: Tokens::new(),
- }
- }
-
- pub(crate) fn finalize(self) -> Tokens {
- let system_array = &csharp::import("global::System", "Array");
- let generic_list = &csharp::import("global::System.Collections.Generic", "List");
-
- quote! {
- public sealed partial class $(self.type_name) : global::Substrate.NetApi.Model.Types.Base.BaseType
- {
- $(self.props_tokens)
-
- $(inheritdoc())
- public override string TypeName() => $(quoted(self.type_name));
-
- $(inheritdoc())
- public override byte[] Encode()
- {
- var result = new $generic_list();
- $(self.encode_tokens)
- return result.ToArray();
- }
-
- $(inheritdoc())
- public override void Decode(byte[] byteArray, ref int p)
- {
- var start = p;
- $(self.decode_tokens)
- var bytesLength = p - start;
- this.TypeSize = bytesLength;
- this.Bytes = new byte[bytesLength];
- $system_array.Copy(byteArray, start, this.Bytes, 0, bytesLength);
- }
- }
- }
- }
-
- fn tuple_struct(&mut self, struct_def: &'a StructDef) {
- if struct_def.fields().is_empty() {
- return;
- }
- let value_type = self.type_generator.generate_struct_def(struct_def);
- quote_in! { self.props_tokens =>
- [System.Diagnostics.CodeAnalysis.AllowNull]$['\r']
- public $(&value_type) Value { get; set; }$['\r']
- };
- quote_in! { self.encode_tokens =>
- result.AddRange(this.Value.Encode());$['\r']
- };
- quote_in! { self.decode_tokens =>
- this.Value = new $(&value_type)();$['\r']
- this.Value.Decode(byteArray, ref p);$['\r']
- };
- }
-}
-
-impl<'a> Visitor<'a> for StructDefGenerator<'a> {
- fn visit_struct_def(&mut self, struct_def: &'a StructDef) {
- let is_regular_struct = struct_def.fields().iter().all(|f| f.name().is_some());
- let is_tuple_struct = struct_def.fields().iter().all(|f| f.name().is_none());
- if !is_regular_struct && !is_tuple_struct {
- panic!("Struct must be either regular or tuple");
- }
- self.is_tuple_struct = is_tuple_struct;
-
- if is_tuple_struct {
- self.tuple_struct(struct_def);
- return;
- }
- visitor::accept_struct_def(struct_def, self);
- }
-
- fn visit_struct_field(&mut self, struct_field: &'a StructField) {
- let type_decl_code = self
- .type_generator
- .generate_type_decl(struct_field.type_decl());
-
- self.props_tokens.push();
- self.props_tokens
- .append(summary_comment(struct_field.docs()));
- self.props_tokens.push();
- if let Some(field_name) = struct_field.name() {
- let field_name_pascal = field_name.to_case(Case::Pascal);
- quote_in! { self.props_tokens =>
- [System.Diagnostics.CodeAnalysis.AllowNull]$['\r']
- public $(&type_decl_code) $(&field_name_pascal) { get; set; }$['\r']
- };
- quote_in! { self.encode_tokens =>
- result.AddRange(this.$(&field_name_pascal).Encode());$['\r']
- };
- quote_in! { self.decode_tokens =>
- this.$(&field_name_pascal) = new $(&type_decl_code)();$['\r']
- this.$(&field_name_pascal).Decode(byteArray, ref p);$['\r']
- };
- }
- }
-}
-
-struct EnumDefGenerator<'a> {
- type_name: &'a str,
- type_generator: TypeDeclGenerator<'a>,
- enum_tokens: Tokens,
- class_tokens: Tokens,
-}
-
-impl<'a> EnumDefGenerator<'a> {
- pub(crate) fn new(type_name: &'a str, type_generator: TypeDeclGenerator<'a>) -> Self {
- Self {
- type_name,
- type_generator,
- enum_tokens: Tokens::new(),
- class_tokens: Tokens::new(),
- }
- }
-
- pub(crate) fn finalize(self) -> Tokens {
- let class_name = format!("Enum{}", self.type_name);
- quote!(
- public enum $(self.type_name)
- {
- $(self.enum_tokens)
- }
-
- public sealed partial class $(&class_name) : global::Substrate.NetApi.Model.Types.Base.BaseEnumRust<$(self.type_name)>
- {
- public $(&class_name)()
- {
- $(self.class_tokens)
- }
- }
- )
- }
-}
-
-impl<'ast> Visitor<'ast> for EnumDefGenerator<'ast> {
- fn visit_enum_variant(&mut self, enum_variant: &'ast EnumVariant) {
- quote_in! { self.enum_tokens =>
- $(summary_comment(enum_variant.docs()))
- $(enum_variant.name()),$['\r']
- };
-
- let type_decl_code = if let Some(type_decl) = enum_variant.type_decl().as_ref() {
- self.type_generator.generate_type_decl(type_decl)
- } else {
- primitive_type_to_dotnet(PrimitiveType::Null).into()
- };
- quote_in! { self.class_tokens =>
- this.AddTypeDecoder<$(type_decl_code)>($(self.type_name).$(enum_variant.name()));$['\r']
- }
- }
-}
-
-#[derive(Clone)]
-pub(crate) struct TypeDeclGenerator<'a> {
- code: String,
- generated_types: &'a Vec<&'a Type>,
-}
-
-impl<'a> TypeDeclGenerator<'a> {
- pub(crate) fn new(generated_types: &'a Vec<&'a Type>) -> Self {
- Self {
- code: String::new(),
- generated_types,
- }
- }
-
- pub(crate) fn generate_type_decl(&mut self, type_decl: &'a TypeDecl) -> String {
- visitor::accept_type_decl(type_decl, self);
- std::mem::take(&mut self.code)
- }
-
- pub(crate) fn generate_struct_def(&mut self, struct_def: &'a StructDef) -> String {
- visitor::accept_struct_def(struct_def, self);
- std::mem::take(&mut self.code)
- }
-
- pub(crate) fn generate_types_as_tuple(&mut self, type_decls: Vec<&'a TypeDecl>) -> String {
- if type_decls.is_empty() {
- } else if type_decls.len() == 1 {
- visitor::accept_type_decl(type_decls[0], self);
- } else {
- self.code.push_str(base!("BaseTuple<"));
- self.join_type_decls(type_decls, ", ");
- self.code.push('>');
- }
- std::mem::take(&mut self.code)
- }
-
- fn join_type_decls>(
- &mut self,
- type_decls: I,
- separator: &str,
- ) {
- let prev_code = std::mem::take(&mut self.code);
- let mut type_decls_str: Vec = Vec::new();
- let iter = type_decls.into_iter();
- for type_decl in iter {
- visitor::accept_type_decl(type_decl, self);
- type_decls_str.push(std::mem::take(&mut self.code));
- }
- _ = std::mem::replace(&mut self.code, prev_code);
- self.code.push_str(type_decls_str.join(separator).as_str());
- }
-
- pub(crate) fn fn_params_with_types(&mut self, params: &'a [FuncParam]) -> String {
- params
- .iter()
- .map(|p| {
- format!(
- "{} {}",
- self.generate_type_decl(p.type_decl()),
- escape_keywords(p.name().to_case(convert_case::Case::Camel))
- )
- })
- .collect::>()
- .join(", ")
- }
-}
-
-impl<'a> Visitor<'a> for TypeDeclGenerator<'a> {
- fn visit_optional_type_decl(&mut self, optional_type_decl: &'a TypeDecl) {
- self.code.push_str(base!("BaseOpt<"));
- visitor::accept_type_decl(optional_type_decl, self);
- self.code.push('>');
- }
-
- fn visit_result_type_decl(&mut self, ok_type_decl: &'a TypeDecl, err_type_decl: &'a TypeDecl) {
- self.code.push_str(client_base!("BaseResult<"));
- visitor::accept_type_decl(ok_type_decl, self);
- self.code.push_str(", ");
- visitor::accept_type_decl(err_type_decl, self);
- self.code.push('>');
- }
-
- fn visit_vector_type_decl(&mut self, vector_type_decl: &'a TypeDecl) {
- self.code.push_str(base!("BaseVec<"));
- visitor::accept_type_decl(vector_type_decl, self);
- self.code.push('>');
- }
-
- fn visit_struct_def(&mut self, struct_def: &'a StructDef) {
- if struct_def.fields().is_empty() {
- return;
- }
- if struct_def.fields().len() == 1 {
- visitor::accept_type_decl(struct_def.fields()[0].type_decl(), self);
- } else {
- self.code.push_str(base!("BaseTuple<"));
- self.join_type_decls(struct_def.fields().iter().map(|f| f.type_decl()), ", ");
- self.code.push('>');
- }
- }
-
- fn visit_primitive_type_id(&mut self, primitive_type_id: PrimitiveType) {
- self.code
- .push_str(primitive_type_to_dotnet(primitive_type_id));
- }
-
- fn visit_user_defined_type_id(&mut self, user_defined_type_id: &'a str) {
- let is_enum = self
- .generated_types
- .iter()
- .find(|&&t| t.name() == user_defined_type_id)
- .map(|&t| matches!(t.def(), TypeDef::Enum(_)))
- .unwrap_or_default();
- let type_id = if is_enum {
- &format!("Enum{}", user_defined_type_id) // Enum prefix
- } else {
- user_defined_type_id
- };
- self.code.push_str(type_id);
- }
-
- fn visit_map_type_decl(&mut self, key_type_decl: &'a TypeDecl, value_type_decl: &'a TypeDecl) {
- self.code.push_str(client_base!("BaseDictionary<"));
- visitor::accept_type_decl(key_type_decl, self);
- self.code.push_str(", ");
- visitor::accept_type_decl(value_type_decl, self);
- self.code.push('>');
- }
-
- fn visit_array_type_decl(&mut self, item_type_decl: &'a TypeDecl, _len: u32) {
- visitor::accept_type_decl(item_type_decl, self);
- self.code.push_str("[]");
- }
-}
-
-pub(crate) fn primitive_type_to_dotnet(primitive_type: PrimitiveType) -> &'static str {
- match primitive_type {
- PrimitiveType::U8 => primitive!("U8"),
- PrimitiveType::U16 => primitive!("U16"),
- PrimitiveType::U32 => primitive!("U32"),
- PrimitiveType::U64 => primitive!("U64"),
- PrimitiveType::U128 => primitive!("U128"),
- PrimitiveType::I8 => primitive!("I8"),
- PrimitiveType::I16 => primitive!("I16"),
- PrimitiveType::I32 => primitive!("I32"),
- PrimitiveType::I64 => primitive!("I64"),
- PrimitiveType::I128 => primitive!("I128"),
- PrimitiveType::Bool => primitive!("Bool"),
- PrimitiveType::Str => primitive!("Str"),
- PrimitiveType::Char => primitive!("PrimChar"),
- PrimitiveType::Null => base!("BaseVoid"),
- PrimitiveType::ActorId => gprimitives!("ActorId"),
- PrimitiveType::CodeId => gprimitives!("CodeId"),
- PrimitiveType::MessageId => gprimitives!("MessageId"),
- PrimitiveType::H160 => client_primitive!("H160"),
- PrimitiveType::H256 => "global::Substrate.Gear.Api.Generated.Model.primitive_types.H256",
- PrimitiveType::U256 => primitive!("U256"),
- PrimitiveType::NonZeroU8 => client_primitive!("NonZeroU8"),
- PrimitiveType::NonZeroU16 => client_primitive!("NonZeroU16"),
- PrimitiveType::NonZeroU32 => "global::Substrate.Gear.Api.Generated.Types.Base.NonZeroU32",
- PrimitiveType::NonZeroU64 => client_primitive!("NonZeroU64"),
- PrimitiveType::NonZeroU128 => client_primitive!("NonZeroU128"),
- PrimitiveType::NonZeroU256 => client_primitive!("NonZeroU256"),
- }
-}
diff --git a/net/rs/client-gen/tests/snapshots/generator__basic_works.snap b/net/rs/client-gen/tests/snapshots/generator__basic_works.snap
index a44d4456..7974674d 100644
--- a/net/rs/client-gen/tests/snapshots/generator__basic_works.snap
+++ b/net/rs/client-gen/tests/snapshots/generator__basic_works.snap
@@ -2,12 +2,15 @@
source: client-gen/tests/generator.rs
expression: "gen(idl, \"Basic\")"
---
+//
using global::Sails.Remoting;
using global::Sails.Remoting.Abstractions;
using global::Sails.Remoting.Abstractions.Core;
using global::System;
using global::System.Collections.Generic;
+#nullable enable
+
#pragma warning disable RCS0056 // A line is too long
namespace Basic.Client;
@@ -23,31 +26,28 @@ ICall DoThat(global::Substrat
public Basic(IRemoting remoting) { this.remoting = remoting; }
///
- public ICall DoThis(global::Substrate.NetApi.Model.Types.Primitive.U32 p1, MyParam p2) { return new RemotingAction( this.remoting, [20, 66, 97, 115, 105, 99, 24, 68, 111, 84, 104, 105, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(p1, p2) ); }
+ public ICall DoThis(global::Substrate.NetApi.Model.Types.Primitive.U32 p1, MyParam p2) { return new RemotingAction(this.remoting, [20, 66, 97, 115, 105, 99, 24, 68, 111, 84, 104, 105, 115], p1, p2); }
///
- public ICall DoThat(global::Substrate.NetApi.Model.Types.Base.BaseTuple p1) { return new RemotingAction( this.remoting, [20, 66, 97, 115, 105, 99, 24, 68, 111, 84, 104, 97, 116], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(p1) ); } }
+ public ICall DoThat(global::Substrate.NetApi.Model.Types.Base.BaseTuple p1) { return new RemotingAction(this.remoting, [20, 66, 97, 115, 105, 99, 24, 68, 111, 84, 104, 97, 116], p1); } }
public sealed partial class MyParam : global::Substrate.NetApi.Model.Types.Base.BaseType {
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Primitive.U32 F1 { get; set; }
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Base.BaseVec F2 { get; set; }
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Base.BaseOpt> F3 { get; set; }
+public global::Substrate.NetApi.Model.Types.Primitive.U32 F1 { get; init; } = new();
+public global::Substrate.NetApi.Model.Types.Base.BaseVec F2 { get; init; } = new();
+public global::Substrate.NetApi.Model.Types.Base.BaseOpt> F3 { get; init; } = new();
///
public override string TypeName() => "MyParam";
///
- public override byte[] Encode() { var result = new List(); result.AddRange(this.F1.Encode());
+ public override byte[] Encode() { var result = new List();
+ result.AddRange(this.F1.Encode());
result.AddRange(this.F2.Encode());
result.AddRange(this.F3.Encode());
- return result.ToArray(); }
+ return result.ToArray();
+ }
///
- public override void Decode(byte[] byteArray, ref int p) { var start = p; this.F1 = new global::Substrate.NetApi.Model.Types.Primitive.U32();
+ public override void Decode(byte[] byteArray, ref int p) { var start = p;
this.F1.Decode(byteArray, ref p);
-this.F2 = new global::Substrate.NetApi.Model.Types.Base.BaseVec();
- this.F2.Decode(byteArray, ref p);
-this.F3 = new global::Substrate.NetApi.Model.Types.Base.BaseOpt>();
- this.F3.Decode(byteArray, ref p);
+this.F2.Decode(byteArray, ref p);
+this.F3.Decode(byteArray, ref p);
var bytesLength = p - start; this.TypeSize = bytesLength; this.Bytes = new byte[bytesLength]; Array.Copy(byteArray, start, this.Bytes, 0, bytesLength); } }
public enum MyParam2 { Variant1,
diff --git a/net/rs/client-gen/tests/snapshots/generator__events_works.snap b/net/rs/client-gen/tests/snapshots/generator__events_works.snap
index 275b8806..277b30b4 100644
--- a/net/rs/client-gen/tests/snapshots/generator__events_works.snap
+++ b/net/rs/client-gen/tests/snapshots/generator__events_works.snap
@@ -2,12 +2,15 @@
source: client-gen/tests/generator.rs
expression: "gen(idl, \"ServiceWithEvents\")"
---
+//
using global::Sails.Remoting;
using global::Sails.Remoting.Abstractions;
using global::Sails.Remoting.Abstractions.Core;
using global::System;
using global::System.Collections.Generic;
+#nullable enable
+
#pragma warning disable RCS0056 // A line is too long
namespace ServiceWithEvents.Client;
@@ -22,7 +25,7 @@ public interface IServiceWithEvents
public ServiceWithEvents(IRemoting remoting) { this.remoting = remoting; }
///
- public ICall DoThis(global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 p1, MyParam p2) { return new RemotingAction( this.remoting, [68, 83, 101, 114, 118, 105, 99, 101, 87, 105, 116, 104, 69, 118, 101, 110, 116, 115, 24, 68, 111, 84, 104, 105, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(p1, p2) ); } }
+ public ICall DoThis(global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 p1, MyParam p2) { return new RemotingAction(this.remoting, [68, 83, 101, 114, 118, 105, 99, 101, 87, 105, 116, 104, 69, 118, 101, 110, 116, 115, 24, 68, 111, 84, 104, 105, 115], p1, p2); } }
public enum ServiceWithEventsEvents { One,
Two,
@@ -45,24 +48,21 @@ this.AddTypeDecoder(ServiceW
public async global::System.Collections.Generic.IAsyncEnumerable ListenAsync([global::System.Runtime.CompilerServices.EnumeratorCancellation] global::System.Threading.CancellationToken cancellationToken = default) { await foreach (var bytes in this.remoting.ListenAsync(cancellationToken)) { byte idx = 0; foreach (var route in EventRoutes) { if (route.Length > bytes.Length) { continue; } if (route.AsSpan().SequenceEqual(bytes.AsSpan()[..route.Length])) { var bytesLength = bytes.Length - route.Length + 1; var data = new byte[bytesLength]; data[0] = idx; Buffer.BlockCopy(bytes, route.Length, data, 1, bytes.Length - route.Length); var p = 0; EnumServiceWithEventsEvents ev = new(); ev.Decode(bytes, ref p); yield return ev; } idx++; } } } }
public sealed partial class MyParam : global::Substrate.NetApi.Model.Types.Base.BaseType {
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 F1 { get; set; }
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Base.BaseVec F2 { get; set; }
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Base.BaseOpt> F3 { get; set; }
+public global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 F1 { get; init; } = new();
+public global::Substrate.NetApi.Model.Types.Base.BaseVec F2 { get; init; } = new();
+public global::Substrate.NetApi.Model.Types.Base.BaseOpt> F3 { get; init; } = new();
///
public override string TypeName() => "MyParam";
///
- public override byte[] Encode() { var result = new List(); result.AddRange(this.F1.Encode());
+ public override byte[] Encode() { var result = new List();
+ result.AddRange(this.F1.Encode());
result.AddRange(this.F2.Encode());
result.AddRange(this.F3.Encode());
- return result.ToArray(); }
+ return result.ToArray();
+ }
///
- public override void Decode(byte[] byteArray, ref int p) { var start = p; this.F1 = new global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256();
+ public override void Decode(byte[] byteArray, ref int p) { var start = p;
this.F1.Decode(byteArray, ref p);
-this.F2 = new global::Substrate.NetApi.Model.Types.Base.BaseVec();
- this.F2.Decode(byteArray, ref p);
-this.F3 = new global::Substrate.NetApi.Model.Types.Base.BaseOpt>();
- this.F3.Decode(byteArray, ref p);
+this.F2.Decode(byteArray, ref p);
+this.F3.Decode(byteArray, ref p);
var bytesLength = p - start; this.TypeSize = bytesLength; this.Bytes = new byte[bytesLength]; Array.Copy(byteArray, start, this.Bytes, 0, bytesLength); } }
diff --git a/net/rs/client-gen/tests/snapshots/generator__full.snap b/net/rs/client-gen/tests/snapshots/generator__full.snap
index 4686e229..2833129d 100644
--- a/net/rs/client-gen/tests/snapshots/generator__full.snap
+++ b/net/rs/client-gen/tests/snapshots/generator__full.snap
@@ -2,12 +2,15 @@
source: client-gen/tests/generator.rs
expression: "gen(IDL, \"Service\")"
---
+//
using global::Sails.Remoting;
using global::Sails.Remoting.Abstractions;
using global::Sails.Remoting.Abstractions.Core;
using global::System;
using global::System.Collections.Generic;
+#nullable enable
+
#pragma warning disable RCS0056 // A line is too long
namespace Service.Client;
@@ -29,7 +32,7 @@ IActivation New(global::Substrate.NetApi.Model.Types.Primitive.U32 a);
{ this.remoting = remoting; }
///
- public IActivation New(global::Substrate.NetApi.Model.Types.Primitive.U32 a) { return new RemotingAction( this.remoting, [12, 78, 101, 119], new global::Substrate.NetApi.Model.Types.Primitive.U32(a)); }
+ public IActivation New(global::Substrate.NetApi.Model.Types.Primitive.U32 a) { return new RemotingAction(this.remoting, [12, 78, 101, 119], a); }
}
@@ -46,13 +49,13 @@ IQuery
- public ICall> DoThis(global::Substrate.NetApi.Model.Types.Primitive.U32 p1, global::Substrate.NetApi.Model.Types.Primitive.Str p2, global::Substrate.NetApi.Model.Types.Base.BaseTuple, global::Substrate.NetApi.Model.Types.Primitive.U8> p3, ThisThatSvcAppTupleStruct p4) { return new RemotingAction>( this.remoting, [28, 83, 101, 114, 118, 105, 99, 101, 24, 68, 111, 84, 104, 105, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(p1, p2, p3, p4) ); }
+ public ICall> DoThis(global::Substrate.NetApi.Model.Types.Primitive.U32 p1, global::Substrate.NetApi.Model.Types.Primitive.Str p2, global::Substrate.NetApi.Model.Types.Base.BaseTuple, global::Substrate.NetApi.Model.Types.Primitive.U8> p3, ThisThatSvcAppTupleStruct p4) { return new RemotingAction>(this.remoting, [28, 83, 101, 114, 118, 105, 99, 101, 24, 68, 111, 84, 104, 105, 115], p1, p2, p3, p4); }
///
- public ICall, global::Substrate.NetApi.Model.Types.Primitive.Str>> DoThat(ThisThatSvcAppDoThatParam param) { return new RemotingAction, global::Substrate.NetApi.Model.Types.Primitive.Str>>( this.remoting, [28, 83, 101, 114, 118, 105, 99, 101, 24, 68, 111, 84, 104, 97, 116], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(param) ); }
+ public ICall, global::Substrate.NetApi.Model.Types.Primitive.Str>> DoThat(ThisThatSvcAppDoThatParam param) { return new RemotingAction, global::Substrate.NetApi.Model.Types.Primitive.Str>>(this.remoting, [28, 83, 101, 114, 118, 105, 99, 101, 24, 68, 111, 84, 104, 97, 116], param); }
///
- public IQuery This(global::Substrate.NetApi.Model.Types.Base.BaseVec v1) { return new RemotingAction( this.remoting, [28, 83, 101, 114, 118, 105, 99, 101, 16, 84, 104, 105, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(v1) ); }
+ public IQuery This(global::Substrate.NetApi.Model.Types.Base.BaseVec v1) { return new RemotingAction(this.remoting, [28, 83, 101, 114, 118, 105, 99, 101, 16, 84, 104, 105, 115], v1); }
///
- public IQuery> That(global::Substrate.NetApi.Model.Types.Base.BaseVoid v1) { return new RemotingAction>( this.remoting, [28, 83, 101, 114, 118, 105, 99, 101, 16, 84, 104, 97, 116], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(v1) ); } }
+ public IQuery> That(global::Substrate.NetApi.Model.Types.Base.BaseVoid v1) { return new RemotingAction>(this.remoting, [28, 83, 101, 114, 118, 105, 99, 101, 16, 84, 104, 97, 116], v1); } }
public enum ServiceEvents {
///
@@ -80,15 +83,16 @@ this.AddTypeDecoder(ServiceE
///
/// ThisThatSvcAppTupleStruct docs
///
-public sealed partial class ThisThatSvcAppTupleStruct : global::Substrate.NetApi.Model.Types.Base.BaseType { [System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Primitive.Bool Value { get; set; }
+public sealed partial class ThisThatSvcAppTupleStruct : global::Substrate.NetApi.Model.Types.Base.BaseType { public global::Substrate.NetApi.Model.Types.Primitive.Bool Value { get; init; } = new();
///
public override string TypeName() => "ThisThatSvcAppTupleStruct";
///
- public override byte[] Encode() { var result = new List(); result.AddRange(this.Value.Encode());
- return result.ToArray(); }
+ public override byte[] Encode() { var result = new List();
+ result.AddRange(this.Value.Encode());
+ return result.ToArray();
+ }
///
- public override void Decode(byte[] byteArray, ref int p) { var start = p; this.Value = new global::Substrate.NetApi.Model.Types.Primitive.Bool();
+ public override void Decode(byte[] byteArray, ref int p) { var start = p;
this.Value.Decode(byteArray, ref p);
var bytesLength = p - start; this.TypeSize = bytesLength; this.Bytes = new byte[bytesLength]; Array.Copy(byteArray, start, this.Bytes, 0, bytesLength); } }
@@ -99,32 +103,29 @@ public sealed partial class ThisThatSvcAppDoThatParam : global::Substrate.NetApi
///
/// field `query`
///
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Primitive.U32 Query { get; set; }
+public global::Substrate.NetApi.Model.Types.Primitive.U32 Query { get; init; } = new();
///
/// field `result`
///
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Primitive.Str Result { get; set; }
+public global::Substrate.NetApi.Model.Types.Primitive.Str Result { get; init; } = new();
///
/// field `p3`
///
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public EnumThisThatSvcAppManyVariants P3 { get; set; }
+public EnumThisThatSvcAppManyVariants P3 { get; init; } = new();
///
public override string TypeName() => "ThisThatSvcAppDoThatParam";
///
- public override byte[] Encode() { var result = new List(); result.AddRange(this.Query.Encode());
+ public override byte[] Encode() { var result = new List();
+ result.AddRange(this.Query.Encode());
result.AddRange(this.Result.Encode());
result.AddRange(this.P3.Encode());
- return result.ToArray(); }
+ return result.ToArray();
+ }
///
- public override void Decode(byte[] byteArray, ref int p) { var start = p; this.Query = new global::Substrate.NetApi.Model.Types.Primitive.U32();
+ public override void Decode(byte[] byteArray, ref int p) { var start = p;
this.Query.Decode(byteArray, ref p);
-this.Result = new global::Substrate.NetApi.Model.Types.Primitive.Str();
- this.Result.Decode(byteArray, ref p);
-this.P3 = new EnumThisThatSvcAppManyVariants();
- this.P3.Decode(byteArray, ref p);
+this.Result.Decode(byteArray, ref p);
+this.P3.Decode(byteArray, ref p);
var bytesLength = p - start; this.TypeSize = bytesLength; this.Bytes = new byte[bytesLength]; Array.Copy(byteArray, start, this.Bytes, 0, bytesLength); } }
///
diff --git a/net/rs/client-gen/tests/snapshots/generator__multiple_services.snap b/net/rs/client-gen/tests/snapshots/generator__multiple_services.snap
index d2185fe8..42051a25 100644
--- a/net/rs/client-gen/tests/snapshots/generator__multiple_services.snap
+++ b/net/rs/client-gen/tests/snapshots/generator__multiple_services.snap
@@ -2,10 +2,13 @@
source: client-gen/tests/generator.rs
expression: "gen(idl, \"Multiple\")"
---
+//
using global::Sails.Remoting;
using global::Sails.Remoting.Abstractions;
using global::Sails.Remoting.Abstractions.Core;
+#nullable enable
+
#pragma warning disable RCS0056 // A line is too long
namespace Multiple.Client;
@@ -21,9 +24,9 @@ ICall DoThat(global::Substrat
public Multiple(IRemoting remoting) { this.remoting = remoting; }
///
- public ICall DoThis(global::Substrate.NetApi.Model.Types.Primitive.U32 p1, MyParam p2) { return new RemotingAction( this.remoting, [32, 77, 117, 108, 116, 105, 112, 108, 101, 24, 68, 111, 84, 104, 105, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(p1, p2) ); }
+ public ICall DoThis(global::Substrate.NetApi.Model.Types.Primitive.U32 p1, MyParam p2) { return new RemotingAction(this.remoting, [32, 77, 117, 108, 116, 105, 112, 108, 101, 24, 68, 111, 84, 104, 105, 115], p1, p2); }
///
- public ICall DoThat(global::Substrate.NetApi.Model.Types.Base.BaseTuple p1) { return new RemotingAction( this.remoting, [32, 77, 117, 108, 116, 105, 112, 108, 101, 24, 68, 111, 84, 104, 97, 116], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(p1) ); } }
+ public ICall DoThat(global::Substrate.NetApi.Model.Types.Base.BaseTuple p1) { return new RemotingAction(this.remoting, [32, 77, 117, 108, 116, 105, 112, 108, 101, 24, 68, 111, 84, 104, 97, 116], p1); } }
public interface INamed
{ IQuery That(global::Substrate.NetApi.Model.Types.Primitive.U32 p1);
@@ -35,4 +38,4 @@ public interface INamed
public Named(IRemoting remoting) { this.remoting = remoting; }
///
- public IQuery That(global::Substrate.NetApi.Model.Types.Primitive.U32 p1) { return new RemotingAction( this.remoting, [20, 78, 97, 109, 101, 100, 16, 84, 104, 97, 116], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(p1) ); } }
+ public IQuery That(global::Substrate.NetApi.Model.Types.Primitive.U32 p1) { return new RemotingAction(this.remoting, [20, 78, 97, 109, 101, 100, 16, 84, 104, 97, 116], p1); } }
diff --git a/net/rs/client-gen/tests/snapshots/generator__nonzero_works.snap b/net/rs/client-gen/tests/snapshots/generator__nonzero_works.snap
index 2a275b62..a9b2f3ab 100644
--- a/net/rs/client-gen/tests/snapshots/generator__nonzero_works.snap
+++ b/net/rs/client-gen/tests/snapshots/generator__nonzero_works.snap
@@ -2,12 +2,15 @@
source: client-gen/tests/generator.rs
expression: "gen(idl, \"NonZeroParams\")"
---
+//
using global::Sails.Remoting;
using global::Sails.Remoting.Abstractions;
using global::Sails.Remoting.Abstractions.Core;
using global::System;
using global::System.Collections.Generic;
+#nullable enable
+
#pragma warning disable RCS0056 // A line is too long
namespace NonZeroParams.Client;
@@ -22,27 +25,24 @@ public interface INonZeroParams
public NonZeroParams(IRemoting remoting) { this.remoting = remoting; }
///
- public ICall DoThis(global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 p1, MyParam p2) { return new RemotingAction( this.remoting, [52, 78, 111, 110, 90, 101, 114, 111, 80, 97, 114, 97, 109, 115, 24, 68, 111, 84, 104, 105, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(p1, p2) ); } }
+ public ICall DoThis(global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 p1, MyParam p2) { return new RemotingAction(this.remoting, [52, 78, 111, 110, 90, 101, 114, 111, 80, 97, 114, 97, 109, 115, 24, 68, 111, 84, 104, 105, 115], p1, p2); } }
public sealed partial class MyParam : global::Substrate.NetApi.Model.Types.Base.BaseType {
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 F1 { get; set; }
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Base.BaseVec F2 { get; set; }
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Base.BaseOpt> F3 { get; set; }
+public global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 F1 { get; init; } = new();
+public global::Substrate.NetApi.Model.Types.Base.BaseVec F2 { get; init; } = new();
+public global::Substrate.NetApi.Model.Types.Base.BaseOpt> F3 { get; init; } = new();
///
public override string TypeName() => "MyParam";
///
- public override byte[] Encode() { var result = new List(); result.AddRange(this.F1.Encode());
+ public override byte[] Encode() { var result = new List();
+ result.AddRange(this.F1.Encode());
result.AddRange(this.F2.Encode());
result.AddRange(this.F3.Encode());
- return result.ToArray(); }
+ return result.ToArray();
+ }
///
- public override void Decode(byte[] byteArray, ref int p) { var start = p; this.F1 = new global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256();
+ public override void Decode(byte[] byteArray, ref int p) { var start = p;
this.F1.Decode(byteArray, ref p);
-this.F2 = new global::Substrate.NetApi.Model.Types.Base.BaseVec();
- this.F2.Decode(byteArray, ref p);
-this.F3 = new global::Substrate.NetApi.Model.Types.Base.BaseOpt>();
- this.F3.Decode(byteArray, ref p);
+this.F2.Decode(byteArray, ref p);
+this.F3.Decode(byteArray, ref p);
var bytesLength = p - start; this.TypeSize = bytesLength; this.Bytes = new byte[bytesLength]; Array.Copy(byteArray, start, this.Bytes, 0, bytesLength); } }
diff --git a/net/rs/client-gen/tests/snapshots/generator__rmrk_works.snap b/net/rs/client-gen/tests/snapshots/generator__rmrk_works.snap
index 18418206..6d04d28b 100644
--- a/net/rs/client-gen/tests/snapshots/generator__rmrk_works.snap
+++ b/net/rs/client-gen/tests/snapshots/generator__rmrk_works.snap
@@ -2,12 +2,15 @@
source: client-gen/tests/generator.rs
expression: "gen(idl, \"RmrkCatalog\")"
---
+//
using global::Sails.Remoting;
using global::Sails.Remoting.Abstractions;
using global::Sails.Remoting.Abstractions.Core;
using global::System;
using global::System.Collections.Generic;
+#nullable enable
+
#pragma warning disable RCS0056 // A line is too long
namespace RmrkCatalog.Client;
@@ -26,7 +29,7 @@ IActivation New();
{ this.remoting = remoting; }
///
- public IActivation New() { return new RemotingAction( this.remoting, [12, 78, 101, 119], new global::Substrate.NetApi.Model.Types.Base.BaseVoid()); }
+ public IActivation New() { return new RemotingAction(this.remoting, [12, 78, 101, 119]); }
}
@@ -47,21 +50,21 @@ IQuery> Part(global::Sub
public RmrkCatalog(IRemoting remoting) { this.remoting = remoting; }
///
- public ICall>, Error>> AddEquippables(global::Substrate.NetApi.Model.Types.Primitive.U32 partId, global::Substrate.NetApi.Model.Types.Base.BaseVec collectionIds) { return new RemotingAction>, Error>>( this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 56, 65, 100, 100, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(partId, collectionIds) ); }
+ public ICall>, Error>> AddEquippables(global::Substrate.NetApi.Model.Types.Primitive.U32 partId, global::Substrate.NetApi.Model.Types.Base.BaseVec collectionIds) { return new RemotingAction>, Error>>(this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 56, 65, 100, 100, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101, 115], partId, collectionIds); }
///
- public ICall, Error>> AddParts(global::Substrate.Gear.Client.NetApi.Model.Types.Base.BaseDictionary parts) { return new RemotingAction, Error>>( this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 32, 65, 100, 100, 80, 97, 114, 116, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(parts) ); }
+ public ICall, Error>> AddParts(global::Substrate.Gear.Client.NetApi.Model.Types.Base.BaseDictionary parts) { return new RemotingAction, Error>>(this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 32, 65, 100, 100, 80, 97, 114, 116, 115], parts); }
///
- public ICall, Error>> RemoveEquippable(global::Substrate.NetApi.Model.Types.Primitive.U32 partId, global::Substrate.Gear.Api.Generated.Model.gprimitives.ActorId collectionId) { return new RemotingAction, Error>>( this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 64, 82, 101, 109, 111, 118, 101, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(partId, collectionId) ); }
+ public ICall, Error>> RemoveEquippable(global::Substrate.NetApi.Model.Types.Primitive.U32 partId, global::Substrate.Gear.Api.Generated.Model.gprimitives.ActorId collectionId) { return new RemotingAction, Error>>(this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 64, 82, 101, 109, 111, 118, 101, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101], partId, collectionId); }
///
- public ICall, Error>> RemoveParts(global::Substrate.NetApi.Model.Types.Base.BaseVec partIds) { return new RemotingAction, Error>>( this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 44, 82, 101, 109, 111, 118, 101, 80, 97, 114, 116, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(partIds) ); }
+ public ICall, Error>> RemoveParts(global::Substrate.NetApi.Model.Types.Base.BaseVec partIds) { return new RemotingAction, Error>>(this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 44, 82, 101, 109, 111, 118, 101, 80, 97, 114, 116, 115], partIds); }
///
- public ICall> ResetEquippables(global::Substrate.NetApi.Model.Types.Primitive.U32 partId) { return new RemotingAction>( this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 64, 82, 101, 115, 101, 116, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(partId) ); }
+ public ICall> ResetEquippables(global::Substrate.NetApi.Model.Types.Primitive.U32 partId) { return new RemotingAction>(this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 64, 82, 101, 115, 101, 116, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101, 115], partId); }
///
- public ICall> SetEquippablesToAll(global::Substrate.NetApi.Model.Types.Primitive.U32 partId) { return new RemotingAction>( this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 76, 83, 101, 116, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101, 115, 84, 111, 65, 108, 108], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(partId) ); }
+ public ICall> SetEquippablesToAll(global::Substrate.NetApi.Model.Types.Primitive.U32 partId) { return new RemotingAction>(this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 76, 83, 101, 116, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101, 115, 84, 111, 65, 108, 108], partId); }
///
- public IQuery> Equippable(global::Substrate.NetApi.Model.Types.Primitive.U32 partId, global::Substrate.Gear.Api.Generated.Model.gprimitives.ActorId collectionId) { return new RemotingAction>( this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 40, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(partId, collectionId) ); }
+ public IQuery> Equippable(global::Substrate.NetApi.Model.Types.Primitive.U32 partId, global::Substrate.Gear.Api.Generated.Model.gprimitives.ActorId collectionId) { return new RemotingAction>(this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 40, 69, 113, 117, 105, 112, 112, 97, 98, 108, 101], partId, collectionId); }
///
- public IQuery> Part(global::Substrate.NetApi.Model.Types.Primitive.U32 partId) { return new RemotingAction>( this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 16, 80, 97, 114, 116], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(partId) ); } }
+ public IQuery> Part(global::Substrate.NetApi.Model.Types.Primitive.U32 partId) { return new RemotingAction>(this.remoting, [44, 82, 109, 114, 107, 67, 97, 116, 97, 108, 111, 103, 16, 80, 97, 114, 116], partId); } }
public enum Error { PartIdCantBeZero,
BadConfig,
@@ -91,56 +94,52 @@ public sealed partial class FixedPart : global::Substrate.NetApi.Model.Types.Bas
/// specifies the stack order of an element.
/// An element with greater stack order is always in front of an element with a lower stack order.
///
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Base.BaseOpt Z { get; set; }
+public global::Substrate.NetApi.Model.Types.Base.BaseOpt Z { get; init; } = new();
///
/// The metadata URI of the part.
///
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Primitive.Str MetadataUri { get; set; }
+public global::Substrate.NetApi.Model.Types.Primitive.Str MetadataUri { get; init; } = new();
///
public override string TypeName() => "FixedPart";
///
- public override byte[] Encode() { var result = new List(); result.AddRange(this.Z.Encode());
+ public override byte[] Encode() { var result = new List();
+ result.AddRange(this.Z.Encode());
result.AddRange(this.MetadataUri.Encode());
- return result.ToArray(); }
+ return result.ToArray();
+ }
///
- public override void Decode(byte[] byteArray, ref int p) { var start = p; this.Z = new global::Substrate.NetApi.Model.Types.Base.BaseOpt();
+ public override void Decode(byte[] byteArray, ref int p) { var start = p;
this.Z.Decode(byteArray, ref p);
-this.MetadataUri = new global::Substrate.NetApi.Model.Types.Primitive.Str();
- this.MetadataUri.Decode(byteArray, ref p);
+this.MetadataUri.Decode(byteArray, ref p);
var bytesLength = p - start; this.TypeSize = bytesLength; this.Bytes = new byte[bytesLength]; Array.Copy(byteArray, start, this.Bytes, 0, bytesLength); } }
public sealed partial class SlotPart : global::Substrate.NetApi.Model.Types.Base.BaseType {
///
/// Array of whitelisted collections that can be equipped in the given slot. Used with slot parts only.
///
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Base.BaseVec Equippable { get; set; }
+public global::Substrate.NetApi.Model.Types.Base.BaseVec Equippable { get; init; } = new();
///
/// An optional zIndex of base part layer.
/// specifies the stack order of an element.
/// An element with greater stack order is always in front of an element with a lower stack order.
///
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Base.BaseOpt Z { get; set; }
+public global::Substrate.NetApi.Model.Types.Base.BaseOpt Z { get; init; } = new();
///
/// The metadata URI of the part.
///
-[System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Primitive.Str MetadataUri { get; set; }
+public global::Substrate.NetApi.Model.Types.Primitive.Str MetadataUri { get; init; } = new();
///
public override string TypeName() => "SlotPart";
///
- public override byte[] Encode() { var result = new List(); result.AddRange(this.Equippable.Encode());
+ public override byte[] Encode() { var result = new List();
+ result.AddRange(this.Equippable.Encode());
result.AddRange(this.Z.Encode());
result.AddRange(this.MetadataUri.Encode());
- return result.ToArray(); }
+ return result.ToArray();
+ }
///
- public override void Decode(byte[] byteArray, ref int p) { var start = p; this.Equippable = new global::Substrate.NetApi.Model.Types.Base.BaseVec();
+ public override void Decode(byte[] byteArray, ref int p) { var start = p;
this.Equippable.Decode(byteArray, ref p);
-this.Z = new global::Substrate.NetApi.Model.Types.Base.BaseOpt();
- this.Z.Decode(byteArray, ref p);
-this.MetadataUri = new global::Substrate.NetApi.Model.Types.Primitive.Str();
- this.MetadataUri.Decode(byteArray, ref p);
+this.Z.Decode(byteArray, ref p);
+this.MetadataUri.Decode(byteArray, ref p);
var bytesLength = p - start; this.TypeSize = bytesLength; this.Bytes = new byte[bytesLength]; Array.Copy(byteArray, start, this.Bytes, 0, bytesLength); } }
diff --git a/net/src/Sails.Remoting/RemotingAction.cs b/net/src/Sails.Remoting/RemotingAction.cs
index 760983b4..20dd4a68 100644
--- a/net/src/Sails.Remoting/RemotingAction.cs
+++ b/net/src/Sails.Remoting/RemotingAction.cs
@@ -11,11 +11,11 @@
namespace Sails.Remoting;
-public sealed class RemotingAction(IRemoting remoting, byte[] route, IType args) : IActivation, IQuery, ICall
+public sealed class RemotingAction(IRemoting remoting, byte[] route, params IType[] args) : IActivation, IQuery, ICall
where T : IType, new()
{
private GasUnit? gasLimit;
- private ValueUnit value = new();
+ private ValueUnit value = new(0);
///
public async Task> ActivateAsync(
@@ -97,11 +97,13 @@ public RemotingAction WithValue(ValueUnit value)
private byte[] EncodePayload()
{
- var encodedArgs = args.Encode();
- var payload = new byte[route.Length + encodedArgs.Length];
- Buffer.BlockCopy(route.ToArray(), 0, payload, 0, route.Length);
- Buffer.BlockCopy(encodedArgs, 0, payload, route.Length, encodedArgs.Length);
- return payload;
+ var byteList = new List();
+ byteList.AddRange(route);
+ foreach (var arg in args)
+ {
+ byteList.AddRange(arg.Encode());
+ }
+ return [.. byteList];
}
private T DecodePayload(byte[] bytes)
diff --git a/net/tests/Sails.Client.Tests/DemoClientTests.cs b/net/tests/Sails.Client.Tests/DemoClientTests.cs
index 9436d718..13d5dd4c 100644
--- a/net/tests/Sails.Client.Tests/DemoClientTests.cs
+++ b/net/tests/Sails.Client.Tests/DemoClientTests.cs
@@ -1,6 +1,3 @@
-using Substrate.Gear.Client.NetApi.Model.Types.Base;
-using Substrate.Gear.Client.NetApi.Model.Types.Primitive;
-
namespace Sails.Client.Tests;
public class DemoClientTests
diff --git a/net/tests/Sails.ClientGenerator.Tests/Snapshots/SailsClientGeneratorTests.Generate_DemoIdl#Demo.g.verified.cs b/net/tests/Sails.ClientGenerator.Tests/Snapshots/SailsClientGeneratorTests.Generate_DemoIdl#Demo.g.verified.cs
index a24206f8..8cfba485 100644
--- a/net/tests/Sails.ClientGenerator.Tests/Snapshots/SailsClientGeneratorTests.Generate_DemoIdl#Demo.g.verified.cs
+++ b/net/tests/Sails.ClientGenerator.Tests/Snapshots/SailsClientGeneratorTests.Generate_DemoIdl#Demo.g.verified.cs
@@ -1,10 +1,12 @@
//HintName: Demo.g.cs
+//
using global::Sails.Remoting;
using global::Sails.Remoting.Abstractions;
using global::Sails.Remoting.Abstractions.Core;
using global::System;
using global::System.Collections.Generic;
+#nullable enable
#pragma warning disable RCS0056 // A line is too long
namespace Sails.ClientGenerator.Tests.Demo;
@@ -31,13 +33,13 @@ public DemoFactory(IRemoting remoting)
///
public IActivation Default()
{
- return new RemotingAction(this.remoting, [28, 68, 101, 102, 97, 117, 108, 116], new global::Substrate.NetApi.Model.Types.Base.BaseVoid());
+ return new RemotingAction(this.remoting, [28, 68, 101, 102, 97, 117, 108, 116]);
}
///
public IActivation New(global::Substrate.NetApi.Model.Types.Base.BaseOpt counter, global::Substrate.NetApi.Model.Types.Base.BaseOpt> dogPosition)
{
- return new RemotingAction, global::Substrate.NetApi.Model.Types.Base.BaseOpt>>>(this.remoting, [12, 78, 101, 119], new global::Substrate.NetApi.Model.Types.Base.BaseTuple, global::Substrate.NetApi.Model.Types.Base.BaseOpt>>(counter, dogPosition));
+ return new RemotingAction(this.remoting, [12, 78, 101, 119], counter, dogPosition);
}
}
@@ -59,19 +61,19 @@ public Counter(IRemoting remoting)
///
public ICall Add(global::Substrate.NetApi.Model.Types.Primitive.U32 value)
{
- return new RemotingAction(this.remoting, [28, 67, 111, 117, 110, 116, 101, 114, 12, 65, 100, 100], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(value));
+ return new RemotingAction(this.remoting, [28, 67, 111, 117, 110, 116, 101, 114, 12, 65, 100, 100], value);
}
///
public ICall Sub(global::Substrate.NetApi.Model.Types.Primitive.U32 value)
{
- return new RemotingAction(this.remoting, [28, 67, 111, 117, 110, 116, 101, 114, 12, 83, 117, 98], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(value));
+ return new RemotingAction(this.remoting, [28, 67, 111, 117, 110, 116, 101, 114, 12, 83, 117, 98], value);
}
///
public IQuery Value()
{
- return new RemotingAction(this.remoting, [28, 67, 111, 117, 110, 116, 101, 114, 20, 86, 97, 108, 117, 101], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction(this.remoting, [28, 67, 111, 117, 110, 116, 101, 114, 20, 86, 97, 108, 117, 101]);
}
}
@@ -154,25 +156,25 @@ public Dog(IRemoting remoting)
///
public ICall MakeSound()
{
- return new RemotingAction(this.remoting, [12, 68, 111, 103, 36, 77, 97, 107, 101, 83, 111, 117, 110, 100], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction(this.remoting, [12, 68, 111, 103, 36, 77, 97, 107, 101, 83, 111, 117, 110, 100]);
}
///
public ICall Walk(global::Substrate.NetApi.Model.Types.Primitive.I32 dx, global::Substrate.NetApi.Model.Types.Primitive.I32 dy)
{
- return new RemotingAction(this.remoting, [12, 68, 111, 103, 16, 87, 97, 108, 107], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(dx, dy));
+ return new RemotingAction(this.remoting, [12, 68, 111, 103, 16, 87, 97, 108, 107], dx, dy);
}
///
public IQuery AvgWeight()
{
- return new RemotingAction(this.remoting, [12, 68, 111, 103, 36, 65, 118, 103, 87, 101, 105, 103, 104, 116], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction(this.remoting, [12, 68, 111, 103, 36, 65, 118, 103, 87, 101, 105, 103, 104, 116]);
}
///
public IQuery> Position()
{
- return new RemotingAction>(this.remoting, [12, 68, 111, 103, 32, 80, 111, 115, 105, 116, 105, 111, 110], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction>(this.remoting, [12, 68, 111, 103, 32, 80, 111, 115, 105, 116, 105, 111, 110]);
}
}
@@ -246,7 +248,7 @@ public PingPong(IRemoting remoting)
///
public ICall> Ping(global::Substrate.NetApi.Model.Types.Primitive.Str input)
{
- return new RemotingAction>(this.remoting, [32, 80, 105, 110, 103, 80, 111, 110, 103, 16, 80, 105, 110, 103], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(input));
+ return new RemotingAction>(this.remoting, [32, 80, 105, 110, 103, 80, 111, 110, 103, 16, 80, 105, 110, 103], input);
}
}
@@ -273,49 +275,49 @@ public References(IRemoting remoting)
///
public ICall Add(global::Substrate.NetApi.Model.Types.Primitive.U32 v)
{
- return new RemotingAction(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 12, 65, 100, 100], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(v));
+ return new RemotingAction(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 12, 65, 100, 100], v);
}
///
public ICall> AddByte(global::Substrate.NetApi.Model.Types.Primitive.U8 @byte)
{
- return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 28, 65, 100, 100, 66, 121, 116, 101], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(@byte));
+ return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 28, 65, 100, 100, 66, 121, 116, 101], @byte);
}
///
public ICall> GuessNum(global::Substrate.NetApi.Model.Types.Primitive.U8 number)
{
- return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 32, 71, 117, 101, 115, 115, 78, 117, 109], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(number));
+ return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 32, 71, 117, 101, 115, 115, 78, 117, 109], number);
}
///
public ICall Incr()
{
- return new RemotingAction(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 16, 73, 110, 99, 114], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 16, 73, 110, 99, 114]);
}
///
public ICall> SetNum(global::Substrate.NetApi.Model.Types.Primitive.U8 number)
{
- return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 24, 83, 101, 116, 78, 117, 109], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(number));
+ return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 24, 83, 101, 116, 78, 117, 109], number);
}
///
public IQuery Baked()
{
- return new RemotingAction(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 20, 66, 97, 107, 101, 100], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 20, 66, 97, 107, 101, 100]);
}
///
public IQuery> LastByte()
{
- return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 32, 76, 97, 115, 116, 66, 121, 116, 101], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 32, 76, 97, 115, 116, 66, 121, 116, 101]);
}
///
public IQuery> Message()
{
- return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 28, 77, 101, 115, 115, 97, 103, 101], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction>(this.remoting, [40, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 28, 77, 101, 115, 115, 97, 103, 101]);
}
}
@@ -339,31 +341,31 @@ public ThisThat(IRemoting remoting)
///
public ICall, global::Substrate.NetApi.Model.Types.Primitive.Str>> DoThat(DoThatParam param)
{
- return new RemotingAction, global::Substrate.NetApi.Model.Types.Primitive.Str>>(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 24, 68, 111, 84, 104, 97, 116], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(param));
+ return new RemotingAction, global::Substrate.NetApi.Model.Types.Primitive.Str>>(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 24, 68, 111, 84, 104, 97, 116], param);
}
///
public ICall> DoThis(global::Substrate.NetApi.Model.Types.Primitive.U32 p1, global::Substrate.NetApi.Model.Types.Primitive.Str p2, global::Substrate.NetApi.Model.Types.Base.BaseTuple, global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU8> p3, TupleStruct p4)
{
- return new RemotingAction>(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 24, 68, 111, 84, 104, 105, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust(p1, p2, p3, p4));
+ return new RemotingAction>(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 24, 68, 111, 84, 104, 105, 115], p1, p2, p3, p4);
}
///
public ICall Noop()
{
- return new RemotingAction(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 16, 78, 111, 111, 112], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 16, 78, 111, 111, 112]);
}
///
public IQuery> That()
{
- return new RemotingAction>(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 16, 84, 104, 97, 116], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction>(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 16, 84, 104, 97, 116]);
}
///
public IQuery This()
{
- return new RemotingAction(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 16, 84, 104, 105, 115], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction(this.remoting, [32, 84, 104, 105, 115, 84, 104, 97, 116, 16, 84, 104, 105, 115]);
}
}
@@ -383,7 +385,7 @@ public ValueFee(IRemoting remoting)
///
public ICall DoSomethingAndTakeFee()
{
- return new RemotingAction(this.remoting, [32, 86, 97, 108, 117, 101, 70, 101, 101, 84, 68, 111, 83, 111, 109, 101, 116, 104, 105, 110, 103, 65, 110, 100, 84, 97, 107, 101, 70, 101, 101], new global::Substrate.NetApi.Model.Types.Base.BaseTupleRust());
+ return new RemotingAction(this.remoting, [32, 86, 97, 108, 117, 101, 70, 101, 101, 84, 68, 111, 83, 111, 109, 101, 116, 104, 105, 110, 103, 65, 110, 100, 84, 97, 107, 101, 70, 101, 101]);
}
}
@@ -441,8 +443,7 @@ public ValueFeeListener(global::Sails.Remoting.Abstractions.Core.IRemotingListen
public sealed partial class ReferenceCount : global::Substrate.NetApi.Model.Types.Base.BaseType
{
- [System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Primitive.U32 Value { get; set; }
+ public global::Substrate.NetApi.Model.Types.Primitive.U32 Value { get; init; } = new();
///
public override string TypeName() => "ReferenceCount";
@@ -458,7 +459,6 @@ public override byte[] Encode()
public override void Decode(byte[] byteArray, ref int p)
{
var start = p;
- this.Value = new global::Substrate.NetApi.Model.Types.Primitive.U32();
this.Value.Decode(byteArray, ref p);
var bytesLength = p - start;
this.TypeSize = bytesLength;
@@ -469,14 +469,9 @@ public override void Decode(byte[] byteArray, ref int p)
public sealed partial class DoThatParam : global::Substrate.NetApi.Model.Types.Base.BaseType
{
- [System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.Gear.Api.Generated.Types.Base.NonZeroU32 P1 { get; set; }
-
- [System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.Gear.Api.Generated.Model.gprimitives.ActorId P2 { get; set; }
-
- [System.Diagnostics.CodeAnalysis.AllowNull]
- public EnumManyVariants P3 { get; set; }
+ public global::Substrate.Gear.Api.Generated.Types.Base.NonZeroU32 P1 { get; init; } = new();
+ public global::Substrate.Gear.Api.Generated.Model.gprimitives.ActorId P2 { get; init; } = new();
+ public EnumManyVariants P3 { get; init; } = new();
///
public override string TypeName() => "DoThatParam";
@@ -494,11 +489,8 @@ public override byte[] Encode()
public override void Decode(byte[] byteArray, ref int p)
{
var start = p;
- this.P1 = new global::Substrate.Gear.Api.Generated.Types.Base.NonZeroU32();
this.P1.Decode(byteArray, ref p);
- this.P2 = new global::Substrate.Gear.Api.Generated.Model.gprimitives.ActorId();
this.P2.Decode(byteArray, ref p);
- this.P3 = new EnumManyVariants();
this.P3.Decode(byteArray, ref p);
var bytesLength = p - start;
this.TypeSize = bytesLength;
@@ -532,8 +524,7 @@ public EnumManyVariants()
public sealed partial class TupleStruct : global::Substrate.NetApi.Model.Types.Base.BaseType
{
- [System.Diagnostics.CodeAnalysis.AllowNull]
- public global::Substrate.NetApi.Model.Types.Primitive.Bool Value { get; set; }
+ public global::Substrate.NetApi.Model.Types.Primitive.Bool Value { get; init; } = new();
///
public override string TypeName() => "TupleStruct";
@@ -549,11 +540,10 @@ public override byte[] Encode()
public override void Decode(byte[] byteArray, ref int p)
{
var start = p;
- this.Value = new global::Substrate.NetApi.Model.Types.Primitive.Bool();
this.Value.Decode(byteArray, ref p);
var bytesLength = p - start;
this.TypeSize = bytesLength;
this.Bytes = new byte[bytesLength];
Array.Copy(byteArray, start, this.Bytes, 0, bytesLength);
}
-}
+}
\ No newline at end of file
diff --git a/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs b/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs
new file mode 100644
index 00000000..991f08f6
--- /dev/null
+++ b/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs
@@ -0,0 +1,6 @@
+[assembly: TestFramework(
+ "Sails.Tests.Shared.XUnit.TestFramework",
+ "Sails.Tests.Shared")]
+
+[assembly: AssemblyFixture(
+ typeof(Sails.DemoClient.Tests._Infra.XUnit.Fixtures.SailsFixture))]
diff --git a/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs b/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs
new file mode 100644
index 00000000..60f4f229
--- /dev/null
+++ b/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs
@@ -0,0 +1,21 @@
+using Sails.DemoClient.Tests._Infra.XUnit.Fixtures;
+
+namespace Sails.DemoClient.Tests;
+
+public sealed class DemoFactoryTests : IAssemblyFixture
+{
+ public DemoFactoryTests(SailsFixture fixture)
+ {
+ this.sailsFixture = fixture;
+ // Assert that IDL file from the Sails.DemoClient project is the same as the one
+ // from the SailsFixture
+ }
+
+ private readonly SailsFixture sailsFixture;
+
+ [Fact]
+ public async Task Test1()
+ {
+ var demoContractCodeId = await this.sailsFixture.GetDemoContractCodeIdAsync();
+ }
+}
diff --git a/net/tests/Sails.DemoClient.Tests/GlobalUsings.cs b/net/tests/Sails.DemoClient.Tests/GlobalUsings.cs
new file mode 100644
index 00000000..8f37676d
--- /dev/null
+++ b/net/tests/Sails.DemoClient.Tests/GlobalUsings.cs
@@ -0,0 +1,3 @@
+global using System.Threading.Tasks;
+global using Sails.Tests.Shared.XUnit;
+global using Xunit;
diff --git a/net/tests/Sails.DemoClient.Tests/Sails.DemoClient.Tests.csproj b/net/tests/Sails.DemoClient.Tests/Sails.DemoClient.Tests.csproj
new file mode 100644
index 00000000..eeb8d95e
--- /dev/null
+++ b/net/tests/Sails.DemoClient.Tests/Sails.DemoClient.Tests.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net8.0
+ false
+ true
+ $(NoWarn);xUnit1041
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/net/tests/Sails.DemoClient.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs b/net/tests/Sails.DemoClient.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs
new file mode 100644
index 00000000..6ec86d5e
--- /dev/null
+++ b/net/tests/Sails.DemoClient.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs
@@ -0,0 +1,9 @@
+namespace Sails.DemoClient.Tests._Infra.XUnit.Fixtures;
+
+public sealed class SailsFixture : Sails.Tests.Shared.XUnit.Fixtures.SailsFixture
+{
+ public SailsFixture()
+ : base("demo-client-tests")
+ {
+ }
+}
diff --git a/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs b/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs
new file mode 100644
index 00000000..32f26ce1
--- /dev/null
+++ b/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs
@@ -0,0 +1,6 @@
+[assembly: TestFramework(
+ "Sails.Tests.Shared.XUnit.TestFramework",
+ "Sails.Tests.Shared")]
+
+[assembly: AssemblyFixture(
+ typeof(Sails.Remoting.Tests._Infra.XUnit.Fixtures.SailsFixture))]
diff --git a/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs b/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs
index 3f603faf..1024a7c7 100644
--- a/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs
+++ b/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs
@@ -1,14 +1,6 @@
using Sails.Remoting.Tests._Infra.XUnit.Fixtures;
-using Substrate.Gear.Api.Generated;
-using Substrate.Gear.Client;
-using Substrate.Gear.Client.Extensions;
using Substrate.Gear.Client.GearApi.Model.gprimitives;
-using Substrate.NET.Schnorrkel.Keys;
-using Substrate.NetApi;
-using Substrate.NetApi.Model.Extrinsics;
-using Substrate.NetApi.Model.Types;
using Substrate.NetApi.Model.Types.Primitive;
-using CodeId = Substrate.Gear.Api.Generated.Model.gprimitives.CodeId;
namespace Sails.Remoting.Tests.Core;
@@ -25,18 +17,9 @@ public RemotingViaNodeClientTests(SailsFixture sailsFixture)
});
var serviceProvider = serviceCollection.BuildServiceProvider();
this.remotingProvider = serviceProvider.GetRequiredService();
- this.remoting = this.remotingProvider.CreateRemoting(AliceAccount);
+ this.remoting = this.remotingProvider.CreateRemoting(SailsFixture.AliceAccount);
}
- private static readonly MiniSecret AliceMiniSecret
- = new(
- Utils.HexToByteArray("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a"),
- ExpandMode.Ed25519);
- private static readonly Account AliceAccount
- = Account.Build(
- KeyType.Sr25519,
- AliceMiniSecret.ExpandToSecret().ToEd25519Bytes(),
- AliceMiniSecret.GetPair().Public.Key);
private static readonly Random Random = new((int)DateTime.UtcNow.Ticks);
private readonly SailsFixture sailsFixture;
@@ -51,8 +34,7 @@ public void Service_Provider_Resolves_Expected_Implementation()
public async Task Program_Activation_Works()
{
// Arrange
- var codeBytes = await this.sailsFixture.GetNoSvcsProgContractWasmAsync();
- var codeId = await this.UploadCodeAsync(codeBytes.AsReadOnlyCollection());
+ var codeId = await this.sailsFixture.GetDemoContractCodeIdAsync();
// Act
var encodedPayload = new Str("Default").Encode();
@@ -63,25 +45,24 @@ public async Task Program_Activation_Works()
CancellationToken.None);
// Assert
- var activationResult = await activationReply.ReadAsync(CancellationToken.None);
+ var (programId, payload) = await activationReply.ReadAsync(CancellationToken.None);
- var programIdStr = activationResult.ProgramId.ToHexString(); // Should be asserted against logs produced by node
+ var programIdStr = programId.ToHexString(); // Should be asserted against logs produced by node
- activationResult.Payload.Should().BeEquivalentTo(encodedPayload, options => options.WithStrictOrdering());
+ payload.Should().BeEquivalentTo(encodedPayload, options => options.WithStrictOrdering());
}
[Fact]
public async Task Sending_Message_To_Program_Works()
{
// Arrange
- var codeBytes = await this.sailsFixture.GetDemoContractWasmAsync();
- var codeId = await this.UploadCodeAsync(codeBytes.AsReadOnlyCollection());
+ var codeId = await this.sailsFixture.GetDemoContractCodeIdAsync();
var activationReply = await this.remoting.ActivateAsync(
codeId,
salt: BitConverter.GetBytes(Random.NextInt64()),
new Str("Default").Encode(),
CancellationToken.None);
- var activationResult = await activationReply.ReadAsync(CancellationToken.None);
+ var (programId, _) = await activationReply.ReadAsync(CancellationToken.None);
// Act
var encodedPayload = new Str("Counter").Encode()
@@ -89,7 +70,7 @@ public async Task Sending_Message_To_Program_Works()
.Concat(new U32(42).Encode())
.ToArray();
var messageReply = await this.remoting.MessageAsync(
- activationResult.ProgramId,
+ programId,
encodedPayload,
CancellationToken.None);
@@ -105,16 +86,15 @@ public async Task Sending_Message_To_Program_Works()
public async Task Querying_Program_State_Works()
{
// Arrange
- var codeBytes = await this.sailsFixture.GetDemoContractWasmAsync();
- var codeId = await this.UploadCodeAsync(codeBytes.AsReadOnlyCollection());
+ var codeId = await this.sailsFixture.GetDemoContractCodeIdAsync();
var activationReply = await this.remoting.ActivateAsync(
codeId,
salt: BitConverter.GetBytes(Random.NextInt64()),
new Str("Default").Encode(),
CancellationToken.None);
- var activationResult = await activationReply.ReadAsync(CancellationToken.None);
+ var (programId, _) = await activationReply.ReadAsync(CancellationToken.None);
var messageReply = await this.remoting.MessageAsync(
- activationResult.ProgramId,
+ programId,
encodedPayload: new Str("Counter").Encode()
.Concat(new Str("Add").Encode())
.Concat(new U32(42).Encode())
@@ -127,28 +107,13 @@ public async Task Querying_Program_State_Works()
.Concat(new Str("Value").Encode())
.ToArray();
var queryResult = await this.remoting.QueryAsync(
- activationResult.ProgramId,
+ programId,
encodedPayload,
CancellationToken.None);
// Assert
queryResult.Should().BeEquivalentTo(
- encodedPayload.Concat(new U32(42).Encode()).ToArray(),
+ [.. encodedPayload, .. new U32(42).Encode()],
options => options.WithStrictOrdering());
}
-
- private async Task UploadCodeAsync(IReadOnlyCollection codeBytes)
- {
- using (var nodeClient = new SubstrateClientExt(
- this.sailsFixture.GearNodeWsUrl,
- ChargeTransactionPayment.Default()))
- {
- await nodeClient.ConnectAsync();
-
- return await nodeClient.UploadCodeAsync(
- AliceAccount,
- codeBytes,
- CancellationToken.None);
- }
- }
}
diff --git a/net/tests/Sails.Remoting.Tests/GlobalUsings.cs b/net/tests/Sails.Remoting.Tests/GlobalUsings.cs
index d22948a8..8310e6fc 100644
--- a/net/tests/Sails.Remoting.Tests/GlobalUsings.cs
+++ b/net/tests/Sails.Remoting.Tests/GlobalUsings.cs
@@ -1,19 +1,12 @@
global using System;
-global using System.Collections.Generic;
-global using System.IO;
global using System.Linq;
-global using System.Text.RegularExpressions;
global using System.Threading;
global using System.Threading.Tasks;
-global using EnsureThat;
global using FluentAssertions;
global using Microsoft.Extensions.DependencyInjection;
global using Sails.Remoting.Abstractions.Core;
global using Sails.Remoting.Core;
global using Sails.Remoting.DependencyInjection;
global using Sails.Remoting.Options;
-global using Sails.Tests.Shared.Containers;
-global using Sails.Tests.Shared.Git;
global using Sails.Tests.Shared.XUnit;
global using Xunit;
-global using Xunit.Abstractions;
diff --git a/net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj b/net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj
index bf619d93..a940f93f 100644
--- a/net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj
+++ b/net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj
@@ -15,7 +15,6 @@
-
all
@@ -24,11 +23,6 @@
-
-
diff --git a/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs b/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs
index 0fa13585..aba7cea8 100644
--- a/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs
+++ b/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs
@@ -1,138 +1,9 @@
-using Nito.AsyncEx;
-using Sails.Remoting.Tests._Infra.XUnit.Fixtures;
+namespace Sails.Remoting.Tests._Infra.XUnit.Fixtures;
-[assembly: AssemblyFixture(typeof(SailsFixture))]
-
-namespace Sails.Remoting.Tests._Infra.XUnit.Fixtures;
-
-public sealed partial class SailsFixture : IAsyncLifetime
+public sealed class SailsFixture : Sails.Tests.Shared.XUnit.Fixtures.SailsFixture
{
public SailsFixture()
- : this(sailsRsVersion: "0.6.3")
- {
- }
-
- public SailsFixture(string sailsRsVersion)
- {
- EnsureArg.IsNotNullOrWhiteSpace(sailsRsVersion, nameof(sailsRsVersion));
-
- this.sailsRsReleaseTag = $"rs/v{sailsRsVersion}";
- this.demoContractIdl = new AsyncLazy(
- () => this.DownloadStringAsset("demo.idl"),
- AsyncLazyFlags.RetryOnFailure);
- this.demoContractWasm = new AsyncLazy(
- () => this.DownloadOctetAsset("demo.wasm"),
- AsyncLazyFlags.RetryOnFailure);
- this.noSvcsProgContractIdl = new AsyncLazy(
- () => this.DownloadStringAsset("no-svcs-prog.idl"),
- AsyncLazyFlags.RetryOnFailure);
- this.noSvcsProgContractWasm = new AsyncLazy(
- () => this.DownloadOctetAsset("no_svcs_prog.wasm"),
- AsyncLazyFlags.RetryOnFailure);
- this.gearNodeContainer = null;
- }
-
- private static readonly GithubDownloader GithubDownloader = new("gear-tech", "sails");
-
- private readonly string sailsRsReleaseTag;
- private readonly AsyncLazy demoContractIdl;
- private readonly AsyncLazy demoContractWasm;
- private readonly AsyncLazy noSvcsProgContractIdl;
- private readonly AsyncLazy noSvcsProgContractWasm;
- private GearNodeContainer? gearNodeContainer;
-
- public Uri GearNodeWsUrl => this.gearNodeContainer?.WsUrl
- ?? throw new InvalidOperationException("Gear node container is not initialized.");
-
- public async Task DisposeAsync()
+ : base("remoting-tests")
{
- if (this.gearNodeContainer is not null)
- {
- await this.gearNodeContainer.DisposeAsync();
- this.gearNodeContainer = null;
- }
- if (this.demoContractWasm.IsStarted)
- {
- await (await this.demoContractWasm).DisposeAsync();
- }
- if (this.noSvcsProgContractWasm.IsStarted)
- {
- await (await this.noSvcsProgContractWasm).DisposeAsync();
- }
}
-
- public async Task InitializeAsync()
- {
- var sailsRsCargoToml = await this.DownloadSailsRsCargoTomlAsync();
-
- var matchResult = GStdDependencyRegex().Match(sailsRsCargoToml);
- if (!matchResult.Success)
- {
- throw new InvalidOperationException(
- $"Failed to find gstd dependency in Cargo.toml by the '{this.sailsRsReleaseTag}' tag.");
- }
- var gearNodeVersion = matchResult.Groups[1].Value;
-
- // The `reuse` parameter can be made configurable if needed
- this.gearNodeContainer = new GearNodeContainer(gearNodeVersion, reuse: true);
- await this.gearNodeContainer.StartAsync();
- }
-
- public Task GetDemoContractIdlAsync()
- => this.demoContractIdl.Task;
-
- public async Task> GetDemoContractWasmAsync()
- {
- var byteStream = await this.demoContractWasm;
- Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue);
- return new ReadOnlyMemory(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length);
- }
-
- public Task GetNoSvcsProgContractIdlAsync()
- => this.noSvcsProgContractIdl.Task;
-
- public async Task> GetNoSvcsProgContractWasmAsync()
- {
- var byteStream = await this.noSvcsProgContractWasm;
- Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue);
- return new ReadOnlyMemory(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length);
- }
-
- private async Task DownloadStringAsset(string assetName)
- {
- var downloadStream = await GithubDownloader.DownloadReleaseAssetAsync(
- this.sailsRsReleaseTag,
- assetName,
- CancellationToken.None);
- using (var reader = new StreamReader(downloadStream, leaveOpen: false))
- {
- return await reader.ReadToEndAsync(CancellationToken.None);
- }
- }
-
- private async Task DownloadOctetAsset(string assetName)
- {
- var downloadStream = await GithubDownloader.DownloadReleaseAssetAsync(
- this.sailsRsReleaseTag,
- assetName,
- CancellationToken.None);
- var memoryStream = new MemoryStream();
- await downloadStream.CopyToAsync(memoryStream);
- return memoryStream;
- }
-
- private async Task DownloadSailsRsCargoTomlAsync()
- {
- var downloadStream = await GithubDownloader.DownloadFileFromTagAsync(
- this.sailsRsReleaseTag,
- "Cargo.toml",
- CancellationToken.None);
- using (var reader = new StreamReader(downloadStream, leaveOpen: false))
- {
- return await reader.ReadToEndAsync(CancellationToken.None);
- }
- }
-
- [GeneratedRegex(@"gstd\s*=\s*""=?(\d+\.\d+\.\d+)""")]
- private static partial Regex GStdDependencyRegex();
}
diff --git a/net/tests/Sails.Remoting.Tests/_Infra/XUnit/TestFramework.cs b/net/tests/Sails.Remoting.Tests/_Infra/XUnit/TestFramework.cs
deleted file mode 100644
index 3580ce24..00000000
--- a/net/tests/Sails.Remoting.Tests/_Infra/XUnit/TestFramework.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-[assembly: TestFramework(
- "Sails.Remoting.Tests._Infra.XUnit.TestFramework",
- "Sails.Remoting.Tests")]
-
-namespace Sails.Remoting.Tests._Infra.XUnit;
-
-internal sealed class TestFramework : Sails.Tests.Shared.XUnit.TestFramework
-{
- public TestFramework(IMessageSink messageSink)
- : base(messageSink)
- {
- }
-}
diff --git a/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs b/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs
index 8205d792..12fbc477 100644
--- a/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs
+++ b/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs
@@ -16,15 +16,16 @@ public sealed class GearNodeContainer : IAsyncDisposable
// TODO: Consider making 'Version' as an optional parameter.
// By default the latest version should be taken which can be determined
// from the downloaded 'Cargo.toml' file.
- public GearNodeContainer(string gearNodeVersion, bool reuse)
+ public GearNodeContainer(string consumerName, string gearNodeVersion, bool reuse)
{
+ EnsureArg.IsNotNullOrWhiteSpace(consumerName, nameof(consumerName));
EnsureArg.IsNotNullOrWhiteSpace(gearNodeVersion, nameof(gearNodeVersion));
this.nodeInitializationDetector = new NodeInitializationDetector();
this.container = new ContainerBuilder()
- .WithName("gear-node-for-tests")
+ .WithName($"gear-node-for-{consumerName.ToLower()}")
.WithImage($"ghcr.io/gear-tech/node:v{gearNodeVersion}")
- .WithPortBinding(RpcPort, RpcPort) // Use WithPortBinding(RpcPort, true) if random host port is required
+ .WithPortBinding(RpcPort, true)
.WithEntrypoint("gear")
.WithCommand(
"--rpc-external", // --rpc-external is required for listening on all interfaces
@@ -38,13 +39,13 @@ public GearNodeContainer(string gearNodeVersion, bool reuse)
}
private const ushort RpcPort = 9944;
- private static readonly TimeSpan NodeInitializationTimeout = TimeSpan.FromSeconds(10);
+ private static readonly TimeSpan NodeInitializationTimeout = TimeSpan.FromSeconds(30);
private readonly NodeInitializationDetector nodeInitializationDetector;
private readonly IContainer container;
private readonly bool reuse;
- public Uri WsUrl => new($"ws://localhost:{this.container.GetMappedPublicPort(9944)}");
+ public Uri WsUrl => new($"ws://localhost:{this.container.GetMappedPublicPort(RpcPort)}");
public ValueTask DisposeAsync()
// Do not dispose container if it is reused otherwise it will be stopped
@@ -57,8 +58,8 @@ public ValueTask DisposeAsync()
public async Task StartAsync()
{
- await this.container.StartAsync();
- await this.nodeInitializationDetector.IsInitializedAsync(NodeInitializationTimeout);
+ await this.container.StartAsync().ConfigureAwait(false);
+ await this.nodeInitializationDetector.IsInitializedAsync(NodeInitializationTimeout).ConfigureAwait(false);
}
private sealed class NodeInitializationDetector : IOutputConsumer
@@ -81,12 +82,12 @@ public NodeInitializationDetector()
public async Task IsInitializedAsync(TimeSpan maxWaitTime)
{
var timeoutTask = Task.Delay(maxWaitTime);
- var completedTask = await Task.WhenAny(this.isNodeInitialized.Task, timeoutTask);
+ var completedTask = await Task.WhenAny(this.isNodeInitialized.Task, timeoutTask).ConfigureAwait(false);
if (completedTask == timeoutTask)
{
this.isNodeInitialized.SetException(
new TimeoutException($"Node initialization timed out after {maxWaitTime}."));
- await this.isNodeInitialized.Task;
+ await this.isNodeInitialized.Task.ConfigureAwait(false);
}
}
diff --git a/net/tests/Sails.Tests.Shared/Sails.Tests.Shared.csproj b/net/tests/Sails.Tests.Shared/Sails.Tests.Shared.csproj
index bf5ab517..2df2bbc5 100644
--- a/net/tests/Sails.Tests.Shared/Sails.Tests.Shared.csproj
+++ b/net/tests/Sails.Tests.Shared/Sails.Tests.Shared.csproj
@@ -8,8 +8,14 @@
+
+
+
+
+
+
diff --git a/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs b/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs
new file mode 100644
index 00000000..c027a967
--- /dev/null
+++ b/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs
@@ -0,0 +1,229 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using EnsureThat;
+using Nito.AsyncEx;
+using Polly;
+using Polly.Retry;
+using Sails.Tests.Shared.Containers;
+using Sails.Tests.Shared.Git;
+using Substrate.Gear.Api.Generated;
+using Substrate.Gear.Api.Generated.Model.gprimitives;
+using Substrate.Gear.Client;
+using Substrate.NET.Schnorrkel.Keys;
+using Substrate.NetApi;
+using Substrate.NetApi.Model.Extrinsics;
+using Substrate.NetApi.Model.Types;
+using Xunit;
+
+namespace Sails.Tests.Shared.XUnit.Fixtures;
+
+public partial class SailsFixture : IAsyncLifetime
+{
+ public SailsFixture(string consumerName)
+ : this(consumerName, sailsRsVersion: "0.6.3")
+ {
+ }
+
+ public SailsFixture(string consumerName, string sailsRsVersion)
+ {
+ EnsureArg.IsNotNullOrWhiteSpace(consumerName, nameof(consumerName));
+ EnsureArg.IsNotNullOrWhiteSpace(sailsRsVersion, nameof(sailsRsVersion));
+
+ this.consumerName = consumerName;
+ this.sailsRsReleaseTag = $"rs/v{sailsRsVersion}";
+ this.demoContractIdl = new AsyncLazy(
+ () => this.DownloadStringAssetAsync("demo.idl"),
+ AsyncLazyFlags.RetryOnFailure);
+ this.demoContractWasm = new AsyncLazy(
+ () => this.DownloadOctetAssetAsync("demo.wasm"),
+ AsyncLazyFlags.RetryOnFailure);
+ this.demoContractCodeId = new AsyncLazy(
+ async () =>
+ {
+ var codeBytes = await this.GetDemoContractWasmAsync().ConfigureAwait(false);
+ return await UploadCodeRetryPolicy.ExecuteAsync(
+ () => this.UploadCodeAsync(codeBytes.ToArray()))
+ .ConfigureAwait(false);
+ },
+ AsyncLazyFlags.RetryOnFailure);
+ this.noSvcsProgContractIdl = new AsyncLazy(
+ () => this.DownloadStringAssetAsync("no-svcs-prog.idl"),
+ AsyncLazyFlags.RetryOnFailure);
+ this.noSvcsProgContractWasm = new AsyncLazy(
+ () => this.DownloadOctetAssetAsync("no_svcs_prog.wasm"),
+ AsyncLazyFlags.RetryOnFailure);
+ this.noSvcsProgContractCodeId = new AsyncLazy(
+ async () =>
+ {
+ var codeBytes = await this.GetNoSvcsProgContractWasmAsync().ConfigureAwait(false);
+ return await UploadCodeRetryPolicy.ExecuteAsync(
+ () => this.UploadCodeAsync(codeBytes.ToArray()))
+ .ConfigureAwait(false);
+ },
+ AsyncLazyFlags.RetryOnFailure);
+ this.gearNodeContainer = null;
+ }
+
+ private static readonly GithubDownloader GithubDownloader = new("gear-tech", "sails");
+ private static readonly AsyncRetryPolicy UploadCodeRetryPolicy = Policy.Handle(
+ exception =>
+ exception.ErrorCode == 1014 && exception.Message.StartsWith("Priority is too low"))
+ .WaitAndRetryAsync(
+ 10,
+ retry => retry * TimeSpan.FromSeconds(1));
+
+ private readonly string consumerName;
+ private readonly string sailsRsReleaseTag;
+ private readonly AsyncLazy demoContractIdl;
+ private readonly AsyncLazy demoContractWasm;
+ private readonly AsyncLazy demoContractCodeId;
+ private readonly AsyncLazy noSvcsProgContractIdl;
+ private readonly AsyncLazy noSvcsProgContractWasm;
+ private readonly AsyncLazy noSvcsProgContractCodeId;
+ private GearNodeContainer? gearNodeContainer;
+
+ public static MiniSecret AliceMiniSecret { get; }
+ = new(
+ // Taken from 'gear key inspect //Alice' output
+ Utils.HexToByteArray("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a"),
+ ExpandMode.Ed25519);
+ public static Account AliceAccount { get; }
+ = Account.Build(
+ KeyType.Sr25519,
+ AliceMiniSecret.ExpandToSecret().ToEd25519Bytes(),
+ AliceMiniSecret.GetPair().Public.Key);
+ public static MiniSecret BobMiniSecret { get; }
+ = new(
+ // Taken from 'gear key inspect //Bob' output
+ Utils.HexToByteArray("0x398f0c28f98885e046333d4a41c19cee4c37368a9832c6502f6cfd182e2aef89"),
+ ExpandMode.Ed25519);
+ public static Account BobAccount { get; }
+ = Account.Build(
+ KeyType.Sr25519,
+ BobMiniSecret.ExpandToSecret().ToEd25519Bytes(),
+ BobMiniSecret.GetPair().Public.Key);
+
+ public Uri GearNodeWsUrl => this.gearNodeContainer?.WsUrl
+ ?? throw new InvalidOperationException("Gear node container is not initialized.");
+
+ public async Task DisposeAsync()
+ {
+ if (this.gearNodeContainer is not null)
+ {
+ await this.gearNodeContainer.DisposeAsync().ConfigureAwait(false);
+ this.gearNodeContainer = null;
+ }
+ if (this.demoContractWasm.IsStarted)
+ {
+ await (await this.demoContractWasm).DisposeAsync().ConfigureAwait(false);
+ }
+ if (this.noSvcsProgContractWasm.IsStarted)
+ {
+ await (await this.noSvcsProgContractWasm).DisposeAsync().ConfigureAwait(false);
+ }
+ }
+
+ public async Task InitializeAsync()
+ {
+ var sailsRsCargoToml = await this.DownloadSailsRsCargoTomlAsync().ConfigureAwait(false);
+
+ var matchResult = GStdDependencyRegex().Match(sailsRsCargoToml);
+ if (!matchResult.Success)
+ {
+ throw new InvalidOperationException(
+ $"Failed to find gstd dependency in Cargo.toml by the '{this.sailsRsReleaseTag}' tag.");
+ }
+ var gearNodeVersion = matchResult.Groups[1].Value;
+
+ // The `reuse` parameter can be made configurable if needed
+ this.gearNodeContainer = new GearNodeContainer(this.consumerName, gearNodeVersion, reuse: true);
+ await this.gearNodeContainer.StartAsync().ConfigureAwait(false);
+ }
+
+ public Task GetDemoContractIdlAsync()
+ => this.demoContractIdl.Task;
+
+ public async Task> GetDemoContractWasmAsync()
+ {
+ var byteStream = await this.demoContractWasm;
+ Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue);
+ return new ReadOnlyMemory(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length);
+ }
+
+ public Task GetDemoContractCodeIdAsync()
+ => this.demoContractCodeId.Task;
+
+ public Task GetNoSvcsProgContractIdlAsync()
+ => this.noSvcsProgContractIdl.Task;
+
+ public async Task> GetNoSvcsProgContractWasmAsync()
+ {
+ var byteStream = await this.noSvcsProgContractWasm;
+ Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue);
+ return new ReadOnlyMemory(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length);
+ }
+
+ public Task GetNoSvcsProgContractCodeIdAsync()
+ => this.noSvcsProgContractCodeId.Task;
+
+ private async Task DownloadStringAssetAsync(string assetName)
+ {
+ var downloadStream = await GithubDownloader.DownloadReleaseAssetAsync(
+ this.sailsRsReleaseTag,
+ assetName,
+ CancellationToken.None)
+ .ConfigureAwait(false);
+ using (var reader = new StreamReader(downloadStream, leaveOpen: false))
+ {
+ return await reader.ReadToEndAsync(CancellationToken.None).ConfigureAwait(false);
+ }
+ }
+
+ private async Task DownloadOctetAssetAsync(string assetName)
+ {
+ var downloadStream = await GithubDownloader.DownloadReleaseAssetAsync(
+ this.sailsRsReleaseTag,
+ assetName,
+ CancellationToken.None)
+ .ConfigureAwait(false);
+ var memoryStream = new MemoryStream();
+ await downloadStream.CopyToAsync(memoryStream).ConfigureAwait(false);
+ return memoryStream;
+ }
+
+ private async Task DownloadSailsRsCargoTomlAsync()
+ {
+ var downloadStream = await GithubDownloader.DownloadFileFromTagAsync(
+ this.sailsRsReleaseTag,
+ "Cargo.toml",
+ CancellationToken.None)
+ .ConfigureAwait(false);
+ using (var reader = new StreamReader(downloadStream, leaveOpen: false))
+ {
+ return await reader.ReadToEndAsync(CancellationToken.None).ConfigureAwait(false);
+ }
+ }
+
+ private async Task UploadCodeAsync(IReadOnlyCollection codeBytes)
+ {
+ using (var nodeClient = new SubstrateClientExt(
+ this.GearNodeWsUrl,
+ ChargeTransactionPayment.Default()))
+ {
+ await nodeClient.ConnectAsync().ConfigureAwait(false);
+
+ return await nodeClient.UploadCodeAsync(
+ AliceAccount,
+ codeBytes,
+ CancellationToken.None)
+ .ConfigureAwait(false);
+ }
+ }
+
+ [GeneratedRegex(@"gstd\s*=\s*""=?(\d+\.\d+\.\d+)""")]
+ private static partial Regex GStdDependencyRegex();
+}
diff --git a/net/tests/Sails.Tests.Shared/XUnit/TestAssemblyRunner.cs b/net/tests/Sails.Tests.Shared/XUnit/TestAssemblyRunner.cs
index 90f4521a..90abc75b 100644
--- a/net/tests/Sails.Tests.Shared/XUnit/TestAssemblyRunner.cs
+++ b/net/tests/Sails.Tests.Shared/XUnit/TestAssemblyRunner.cs
@@ -30,7 +30,7 @@ public TestAssemblyRunner(
protected override async Task AfterTestAssemblyStartingAsync()
{
- await base.AfterTestAssemblyStartingAsync();
+ await base.AfterTestAssemblyStartingAsync().ConfigureAwait(false);
var requiredFixtureTypes = new HashSet();
@@ -71,7 +71,7 @@ protected override async Task AfterTestAssemblyStartingAsync()
foreach (var initializable in this.assemblyFixtureMappings.Values.OfType())
{
- await this.Aggregator.RunAsync(initializable.InitializeAsync);
+ await this.Aggregator.RunAsync(initializable.InitializeAsync).ConfigureAwait(false);
}
}
diff --git a/net/tests/Sails.Tests.Shared/XUnit/TestFramework.cs b/net/tests/Sails.Tests.Shared/XUnit/TestFramework.cs
index 18820c25..13956cfb 100644
--- a/net/tests/Sails.Tests.Shared/XUnit/TestFramework.cs
+++ b/net/tests/Sails.Tests.Shared/XUnit/TestFramework.cs
@@ -4,9 +4,9 @@
namespace Sails.Tests.Shared.XUnit;
-public abstract class TestFramework : XunitTestFramework
+public class TestFramework : XunitTestFramework
{
- protected TestFramework(IMessageSink messageSink)
+ public TestFramework(IMessageSink messageSink)
: base(messageSink)
{
}
diff --git a/net/tests/Sails.Tests.Shared/XUnit/TestFrameworkExecutor.cs b/net/tests/Sails.Tests.Shared/XUnit/TestFrameworkExecutor.cs
index be9079e6..55a424ce 100644
--- a/net/tests/Sails.Tests.Shared/XUnit/TestFrameworkExecutor.cs
+++ b/net/tests/Sails.Tests.Shared/XUnit/TestFrameworkExecutor.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Xunit.Abstractions;
using Xunit.Sdk;
@@ -15,6 +16,9 @@ public TestFrameworkExecutor(
{
}
+ [SuppressMessage(
+ "Usage", "VSTHRD100:Avoid async void methods",
+ Justification = "All exceptions should be added into the aggregator")]
protected override async void RunTestCases(
IEnumerable testCases,
IMessageSink executionMessageSink,
@@ -27,7 +31,7 @@ protected override async void RunTestCases(
executionMessageSink,
executionOptions))
{
- await assemblyRunner.RunAsync();
+ await assemblyRunner.RunAsync().ConfigureAwait(false);
}
}
}
diff --git a/nuget.config b/nuget.config
new file mode 100644
index 00000000..67eb9d4d
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+