mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-09-17 11:17:28 +03:00
parent
f98e1b128c
commit
1dd722c4a7
@ -2,39 +2,82 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use heck::{ToLowerCamelCase, ToSnakeCase};
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
ext::IdentExt,
|
||||
parse::{Parse, ParseBuffer},
|
||||
parse::{Parse, ParseStream},
|
||||
parse_macro_input,
|
||||
spanned::Spanned,
|
||||
FnArg, Ident, ItemFn, Pat, Token, Visibility,
|
||||
FnArg, Ident, ItemFn, Lit, Meta, Pat, Token, Visibility,
|
||||
};
|
||||
|
||||
struct WrapperAttributes {
|
||||
execution_context: ExecutionContext,
|
||||
argument_case: ArgumentCase,
|
||||
}
|
||||
|
||||
impl Parse for WrapperAttributes {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let mut wrapper_attributes = WrapperAttributes {
|
||||
execution_context: ExecutionContext::Blocking,
|
||||
argument_case: ArgumentCase::Camel,
|
||||
};
|
||||
|
||||
loop {
|
||||
match input.parse::<Meta>() {
|
||||
Ok(Meta::List(_)) => {}
|
||||
Ok(Meta::NameValue(v)) => {
|
||||
if v.path.is_ident("rename_all") {
|
||||
if let Lit::Str(s) = v.lit {
|
||||
wrapper_attributes.argument_case = match s.value().as_str() {
|
||||
"snake_case" => ArgumentCase::Snake,
|
||||
"camelCase" => ArgumentCase::Camel,
|
||||
_ => {
|
||||
return Err(syn::Error::new(
|
||||
s.span(),
|
||||
"expected \"camelCase\" or \"snake_case\"",
|
||||
))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Meta::Path(p)) => {
|
||||
if p.is_ident("async") {
|
||||
wrapper_attributes.execution_context = ExecutionContext::Async;
|
||||
} else {
|
||||
return Err(syn::Error::new(p.span(), "expected `async`"));
|
||||
}
|
||||
}
|
||||
Err(_e) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(Token![,]) {
|
||||
input.parse::<Token![,]>()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(wrapper_attributes)
|
||||
}
|
||||
}
|
||||
|
||||
/// The execution context of the command.
|
||||
enum ExecutionContext {
|
||||
Async,
|
||||
Blocking,
|
||||
}
|
||||
|
||||
impl Parse for ExecutionContext {
|
||||
fn parse(input: &ParseBuffer<'_>) -> syn::Result<Self> {
|
||||
if input.is_empty() {
|
||||
return Ok(Self::Blocking);
|
||||
}
|
||||
|
||||
input
|
||||
.parse::<Token![async]>()
|
||||
.map(|_| Self::Async)
|
||||
.map_err(|_| {
|
||||
syn::Error::new(
|
||||
input.span(),
|
||||
"only a single item `async` is currently allowed",
|
||||
)
|
||||
})
|
||||
}
|
||||
/// The case of each argument name.
|
||||
#[derive(Copy, Clone)]
|
||||
enum ArgumentCase {
|
||||
Snake,
|
||||
Camel,
|
||||
}
|
||||
|
||||
/// The bindings we attach to `tauri::Invoke`.
|
||||
@ -61,14 +104,16 @@ pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream {
|
||||
};
|
||||
|
||||
// body to the command wrapper or a `compile_error!` of an error occurred while parsing it.
|
||||
let body = syn::parse::<ExecutionContext>(attributes)
|
||||
.map(|context| match function.sig.asyncness {
|
||||
Some(_) => ExecutionContext::Async,
|
||||
None => context,
|
||||
let body = syn::parse::<WrapperAttributes>(attributes)
|
||||
.map(|mut attrs| {
|
||||
if function.sig.asyncness.is_some() {
|
||||
attrs.execution_context = ExecutionContext::Async;
|
||||
}
|
||||
attrs
|
||||
})
|
||||
.and_then(|context| match context {
|
||||
ExecutionContext::Async => body_async(&function, &invoke),
|
||||
ExecutionContext::Blocking => body_blocking(&function, &invoke),
|
||||
.and_then(|attrs| match attrs.execution_context {
|
||||
ExecutionContext::Async => body_async(&function, &invoke, attrs.argument_case),
|
||||
ExecutionContext::Blocking => body_blocking(&function, &invoke, attrs.argument_case),
|
||||
})
|
||||
.unwrap_or_else(syn::Error::into_compile_error);
|
||||
|
||||
@ -105,9 +150,9 @@ pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream {
|
||||
/// See the [`tauri::command`] module for all the items and traits that make this possible.
|
||||
///
|
||||
/// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html
|
||||
fn body_async(function: &ItemFn, invoke: &Invoke) -> syn::Result<TokenStream2> {
|
||||
fn body_async(function: &ItemFn, invoke: &Invoke, case: ArgumentCase) -> syn::Result<TokenStream2> {
|
||||
let Invoke { message, resolver } = invoke;
|
||||
parse_args(function, message).map(|args| {
|
||||
parse_args(function, message, case).map(|args| {
|
||||
quote! {
|
||||
#resolver.respond_async_serialized(async move {
|
||||
let result = $path(#(#args?),*);
|
||||
@ -123,9 +168,13 @@ fn body_async(function: &ItemFn, invoke: &Invoke) -> syn::Result<TokenStream2> {
|
||||
/// See the [`tauri::command`] module for all the items and traits that make this possible.
|
||||
///
|
||||
/// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html
|
||||
fn body_blocking(function: &ItemFn, invoke: &Invoke) -> syn::Result<TokenStream2> {
|
||||
fn body_blocking(
|
||||
function: &ItemFn,
|
||||
invoke: &Invoke,
|
||||
case: ArgumentCase,
|
||||
) -> syn::Result<TokenStream2> {
|
||||
let Invoke { message, resolver } = invoke;
|
||||
let args = parse_args(function, message)?;
|
||||
let args = parse_args(function, message, case)?;
|
||||
|
||||
// the body of a `match` to early return any argument that wasn't successful in parsing.
|
||||
let match_body = quote!({
|
||||
@ -141,17 +190,26 @@ fn body_blocking(function: &ItemFn, invoke: &Invoke) -> syn::Result<TokenStream2
|
||||
}
|
||||
|
||||
/// Parse all arguments for the command wrapper to use from the signature of the command function.
|
||||
fn parse_args(function: &ItemFn, message: &Ident) -> syn::Result<Vec<TokenStream2>> {
|
||||
fn parse_args(
|
||||
function: &ItemFn,
|
||||
message: &Ident,
|
||||
case: ArgumentCase,
|
||||
) -> syn::Result<Vec<TokenStream2>> {
|
||||
function
|
||||
.sig
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|arg| parse_arg(&function.sig.ident, arg, message))
|
||||
.map(|arg| parse_arg(&function.sig.ident, arg, message, case))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Transform a [`FnArg`] into a command argument.
|
||||
fn parse_arg(command: &Ident, arg: &FnArg, message: &Ident) -> syn::Result<TokenStream2> {
|
||||
fn parse_arg(
|
||||
command: &Ident,
|
||||
arg: &FnArg,
|
||||
message: &Ident,
|
||||
case: ArgumentCase,
|
||||
) -> syn::Result<TokenStream2> {
|
||||
// we have no use for self arguments
|
||||
let mut arg = match arg {
|
||||
FnArg::Typed(arg) => arg.pat.as_ref().clone(),
|
||||
@ -185,9 +243,13 @@ fn parse_arg(command: &Ident, arg: &FnArg, message: &Ident) -> syn::Result<Token
|
||||
));
|
||||
}
|
||||
|
||||
// snake_case -> camelCase
|
||||
if key.as_str().contains('_') {
|
||||
key = snake_case_to_camel_case(key.as_str());
|
||||
match case {
|
||||
ArgumentCase::Camel => {
|
||||
key = key.to_lower_camel_case();
|
||||
}
|
||||
ArgumentCase::Snake => {
|
||||
key = key.to_snake_case();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(quote!(::tauri::command::CommandArg::from_command(
|
||||
@ -198,19 +260,3 @@ fn parse_arg(command: &Ident, arg: &FnArg, message: &Ident) -> syn::Result<Token
|
||||
}
|
||||
)))
|
||||
}
|
||||
|
||||
/// Convert a snake_case string into camelCase, no underscores will be left.
|
||||
fn snake_case_to_camel_case(key: &str) -> String {
|
||||
let mut camel = String::with_capacity(key.len());
|
||||
let mut to_upper = false;
|
||||
|
||||
for c in key.chars() {
|
||||
match c {
|
||||
'_' => to_upper = true,
|
||||
c if std::mem::take(&mut to_upper) => camel.push(c.to_ascii_uppercase()),
|
||||
c => camel.push(c),
|
||||
}
|
||||
}
|
||||
|
||||
camel
|
||||
}
|
||||
|
@ -17,11 +17,11 @@ pub fn message(_argument: String) {}
|
||||
pub fn resolver(_argument: String) {}
|
||||
|
||||
#[command]
|
||||
pub fn simple_command(argument: String) {
|
||||
println!("{}", argument);
|
||||
pub fn simple_command(the_argument: String) {
|
||||
println!("{}", the_argument);
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub fn stateful_command(argument: Option<String>, state: State<'_, super::MyState>) {
|
||||
println!("{:?} {:?}", argument, state.inner());
|
||||
pub fn stateful_command(the_argument: Option<String>, state: State<'_, super::MyState>) {
|
||||
println!("{:?} {:?}", the_argument, state.inner());
|
||||
}
|
||||
|
@ -1,68 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tauri</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Tauri Commands</h1>
|
||||
<div>Response: <span id="response"></span></div>
|
||||
<div>Without Args: <span id="response-optional"></span></div>
|
||||
<div id="container"></div>
|
||||
<script>
|
||||
function runCommand(commandName, args, optional) {
|
||||
const id = optional ? '#response-optional' : '#response'
|
||||
const result = document.querySelector(id)
|
||||
window.__TAURI__
|
||||
.invoke(commandName, args)
|
||||
.then((response) => {
|
||||
result.innerText = `Ok(${response})`
|
||||
})
|
||||
.catch((error) => {
|
||||
result.innerText = `Err(${error})`
|
||||
})
|
||||
}
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tauri</title>
|
||||
</head>
|
||||
|
||||
const container = document.querySelector('#container')
|
||||
const commands = [
|
||||
{ name: 'borrow_cmd' },
|
||||
{ name: 'window_label' },
|
||||
{ name: 'simple_command' },
|
||||
{ name: 'stateful_command' },
|
||||
{ name: 'async_simple_command' },
|
||||
{ name: 'future_simple_command' },
|
||||
{ name: 'async_stateful_command' },
|
||||
{ name: 'simple_command_with_result' },
|
||||
{ name: 'stateful_command_with_result' },
|
||||
{ name: 'async_simple_command_with_result' },
|
||||
{ name: 'future_simple_command_with_return' },
|
||||
{ name: 'future_simple_command_with_result' },
|
||||
{ name: 'async_stateful_command_with_result' },
|
||||
{ name: 'command_arguments_wild' },
|
||||
{
|
||||
name: 'command_arguments_struct',
|
||||
args: { Person: { name: 'ferris', age: 6 } }
|
||||
},
|
||||
{
|
||||
name: 'command_arguments_tuple_struct',
|
||||
args: { InlinePerson: ['ferris', 6] }
|
||||
}
|
||||
]
|
||||
|
||||
for (const command of commands) {
|
||||
const { name } = command
|
||||
const args = command.args ?? { argument: 'value' }
|
||||
const button = document.createElement('button')
|
||||
button.innerHTML = `Run ${name}`
|
||||
button.addEventListener('click', function () {
|
||||
runCommand(name, args, false)
|
||||
runCommand(name, Object.create(null), true)
|
||||
<body>
|
||||
<h1>Tauri Commands</h1>
|
||||
<div>Response: <span id="response"></span></div>
|
||||
<div>Without Args: <span id="response-optional"></span></div>
|
||||
<div id="container"></div>
|
||||
<script>
|
||||
function runCommand(commandName, args, optional) {
|
||||
const id = optional ? '#response-optional' : '#response'
|
||||
const result = document.querySelector(id)
|
||||
window.__TAURI__
|
||||
.invoke(commandName, args)
|
||||
.then((response) => {
|
||||
result.innerText = `Ok(${response})`
|
||||
})
|
||||
container.appendChild(button)
|
||||
.catch((error) => {
|
||||
result.innerText = `Err(${error})`
|
||||
})
|
||||
}
|
||||
|
||||
const container = document.querySelector('#container')
|
||||
const commands = [
|
||||
{ name: 'borrow_cmd' },
|
||||
{ name: 'window_label' },
|
||||
{ name: 'simple_command' },
|
||||
{ name: 'stateful_command' },
|
||||
{ name: 'async_simple_command' },
|
||||
{ name: 'async_simple_command_snake' },
|
||||
{ name: 'future_simple_command' },
|
||||
{ name: 'async_stateful_command' },
|
||||
{ name: 'simple_command_with_result' },
|
||||
// snake
|
||||
{ name: 'future_simple_command_snake' },
|
||||
{ name: 'future_simple_command_with_return_snake' },
|
||||
{ name: 'future_simple_command_with_result_snake' },
|
||||
{ name: 'force_async_snake' },
|
||||
{ name: 'force_async_with_result_snake' },
|
||||
{ name: 'simple_command_with_result_snake' },
|
||||
{ name: 'stateful_command_with_result_snake' },
|
||||
// state
|
||||
{ name: 'stateful_command_with_result' },
|
||||
{ name: 'async_simple_command_with_result' },
|
||||
{ name: 'future_simple_command_with_return' },
|
||||
{ name: 'future_simple_command_with_result' },
|
||||
{ name: 'async_stateful_command_with_result' },
|
||||
{ name: 'command_arguments_wild' },
|
||||
{
|
||||
name: 'command_arguments_struct',
|
||||
args: { Person: { name: 'ferris', age: 6 } }
|
||||
},
|
||||
{
|
||||
name: 'command_arguments_tuple_struct',
|
||||
args: { InlinePerson: ['ferris', 6] }
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
]
|
||||
|
||||
for (const command of commands) {
|
||||
const { name } = command
|
||||
const args = command.args ?? { [name.endsWith('snake') ? 'the_argument' : 'theArgument']: 'value' }
|
||||
const button = document.createElement('button')
|
||||
button.innerHTML = `Run ${name}`
|
||||
button.addEventListener('click', function () {
|
||||
runCommand(name, args, false)
|
||||
runCommand(name, Object.create(null), true)
|
||||
})
|
||||
container.appendChild(button)
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -36,88 +36,148 @@ fn window_label(window: Window) {
|
||||
// Async commands
|
||||
|
||||
#[command]
|
||||
async fn async_simple_command(argument: String) {
|
||||
println!("{}", argument);
|
||||
async fn async_simple_command(the_argument: String) {
|
||||
println!("{}", the_argument);
|
||||
}
|
||||
|
||||
#[command(rename_all = "snake_case")]
|
||||
async fn async_simple_command_snake(the_argument: String) {
|
||||
println!("{}", the_argument);
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn async_stateful_command(
|
||||
argument: Option<String>,
|
||||
the_argument: Option<String>,
|
||||
state: State<'_, MyState>,
|
||||
) -> Result<(), ()> {
|
||||
println!("{:?} {:?}", argument, state.inner());
|
||||
println!("{:?} {:?}", the_argument, state.inner());
|
||||
Ok(())
|
||||
}
|
||||
// ------------------------ Raw future commands ------------------------
|
||||
|
||||
// Raw future commands
|
||||
#[command(async)]
|
||||
fn future_simple_command(argument: String) -> impl std::future::Future<Output = ()> {
|
||||
println!("{}", argument);
|
||||
fn future_simple_command(the_argument: String) -> impl std::future::Future<Output = ()> {
|
||||
println!("{}", the_argument);
|
||||
std::future::ready(())
|
||||
}
|
||||
|
||||
#[command(async)]
|
||||
fn future_simple_command_with_return(
|
||||
argument: String,
|
||||
the_argument: String,
|
||||
) -> impl std::future::Future<Output = String> {
|
||||
println!("{}", argument);
|
||||
std::future::ready(argument)
|
||||
println!("{}", the_argument);
|
||||
std::future::ready(the_argument)
|
||||
}
|
||||
|
||||
#[command(async)]
|
||||
fn future_simple_command_with_result(
|
||||
argument: String,
|
||||
the_argument: String,
|
||||
) -> impl std::future::Future<Output = Result<String, ()>> {
|
||||
println!("{}", argument);
|
||||
std::future::ready(Ok(argument))
|
||||
println!("{}", the_argument);
|
||||
std::future::ready(Ok(the_argument))
|
||||
}
|
||||
|
||||
#[command(async)]
|
||||
fn force_async(argument: String) -> String {
|
||||
argument
|
||||
fn force_async(the_argument: String) -> String {
|
||||
the_argument
|
||||
}
|
||||
|
||||
#[command(async)]
|
||||
fn force_async_with_result(argument: &str) -> Result<&str, MyError> {
|
||||
(!argument.is_empty())
|
||||
.then(|| argument)
|
||||
fn force_async_with_result(the_argument: &str) -> Result<&str, MyError> {
|
||||
(!the_argument.is_empty())
|
||||
.then(|| the_argument)
|
||||
.ok_or(MyError::FooError)
|
||||
}
|
||||
|
||||
// ------------------------ Raw future commands - snake_case ------------------------
|
||||
|
||||
#[command(async, rename_all = "snake_case")]
|
||||
fn future_simple_command_snake(the_argument: String) -> impl std::future::Future<Output = ()> {
|
||||
println!("{}", the_argument);
|
||||
std::future::ready(())
|
||||
}
|
||||
|
||||
#[command(async, rename_all = "snake_case")]
|
||||
fn future_simple_command_with_return_snake(
|
||||
the_argument: String,
|
||||
) -> impl std::future::Future<Output = String> {
|
||||
println!("{}", the_argument);
|
||||
std::future::ready(the_argument)
|
||||
}
|
||||
|
||||
#[command(async, rename_all = "snake_case")]
|
||||
fn future_simple_command_with_result_snake(
|
||||
the_argument: String,
|
||||
) -> impl std::future::Future<Output = Result<String, ()>> {
|
||||
println!("{}", the_argument);
|
||||
std::future::ready(Ok(the_argument))
|
||||
}
|
||||
|
||||
#[command(async, rename_all = "snake_case")]
|
||||
fn force_async_snake(the_argument: String) -> String {
|
||||
the_argument
|
||||
}
|
||||
|
||||
#[command(rename_all = "snake_case", async)]
|
||||
fn force_async_with_result_snake(the_argument: &str) -> Result<&str, MyError> {
|
||||
(!the_argument.is_empty())
|
||||
.then(|| the_argument)
|
||||
.ok_or(MyError::FooError)
|
||||
}
|
||||
|
||||
// ------------------------ Commands returning Result ------------------------
|
||||
|
||||
#[command]
|
||||
fn simple_command_with_result(argument: String) -> Result<String, MyError> {
|
||||
println!("{}", argument);
|
||||
(!argument.is_empty())
|
||||
.then(|| argument)
|
||||
fn simple_command_with_result(the_argument: String) -> Result<String, MyError> {
|
||||
println!("{}", the_argument);
|
||||
(!the_argument.is_empty())
|
||||
.then(|| the_argument)
|
||||
.ok_or(MyError::FooError)
|
||||
}
|
||||
|
||||
#[command]
|
||||
fn stateful_command_with_result(
|
||||
argument: Option<String>,
|
||||
the_argument: Option<String>,
|
||||
state: State<'_, MyState>,
|
||||
) -> Result<String, MyError> {
|
||||
println!("{:?} {:?}", argument, state.inner());
|
||||
dbg!(argument.ok_or(MyError::FooError))
|
||||
println!("{:?} {:?}", the_argument, state.inner());
|
||||
dbg!(the_argument.ok_or(MyError::FooError))
|
||||
}
|
||||
|
||||
// ------------------------ Commands returning Result - snake_case ------------------------
|
||||
|
||||
#[command(rename_all = "snake_case")]
|
||||
fn simple_command_with_result_snake(the_argument: String) -> Result<String, MyError> {
|
||||
println!("{}", the_argument);
|
||||
(!the_argument.is_empty())
|
||||
.then(|| the_argument)
|
||||
.ok_or(MyError::FooError)
|
||||
}
|
||||
|
||||
#[command(rename_all = "snake_case")]
|
||||
fn stateful_command_with_result_snake(
|
||||
the_argument: Option<String>,
|
||||
state: State<'_, MyState>,
|
||||
) -> Result<String, MyError> {
|
||||
println!("{:?} {:?}", the_argument, state.inner());
|
||||
dbg!(the_argument.ok_or(MyError::FooError))
|
||||
}
|
||||
|
||||
// Async commands
|
||||
|
||||
#[command]
|
||||
async fn async_simple_command_with_result(argument: String) -> Result<String, MyError> {
|
||||
println!("{}", argument);
|
||||
Ok(argument)
|
||||
async fn async_simple_command_with_result(the_argument: String) -> Result<String, MyError> {
|
||||
println!("{}", the_argument);
|
||||
Ok(the_argument)
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn async_stateful_command_with_result(
|
||||
argument: Option<String>,
|
||||
the_argument: Option<String>,
|
||||
state: State<'_, MyState>,
|
||||
) -> Result<String, MyError> {
|
||||
println!("{:?} {:?}", argument, state.inner());
|
||||
Ok(argument.unwrap_or_else(|| "".to_string()))
|
||||
println!("{:?} {:?}", the_argument, state.inner());
|
||||
Ok(the_argument.unwrap_or_else(|| "".to_string()))
|
||||
}
|
||||
|
||||
// Non-Ident command function arguments
|
||||
@ -147,13 +207,13 @@ fn command_arguments_tuple_struct(InlinePerson(name, age): InlinePerson<'_>) {
|
||||
}
|
||||
|
||||
#[command]
|
||||
fn borrow_cmd(argument: &str) -> &str {
|
||||
argument
|
||||
fn borrow_cmd(the_argument: &str) -> &str {
|
||||
the_argument
|
||||
}
|
||||
|
||||
#[command]
|
||||
fn borrow_cmd_async(argument: &str) -> &str {
|
||||
argument
|
||||
fn borrow_cmd_async(the_argument: &str) -> &str {
|
||||
the_argument
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -180,6 +240,14 @@ fn main() {
|
||||
command_arguments_wild,
|
||||
command_arguments_struct,
|
||||
simple_command_with_result,
|
||||
async_simple_command_snake,
|
||||
future_simple_command_snake,
|
||||
future_simple_command_with_return_snake,
|
||||
future_simple_command_with_result_snake,
|
||||
force_async_snake,
|
||||
force_async_with_result_snake,
|
||||
simple_command_with_result_snake,
|
||||
stateful_command_with_result_snake,
|
||||
stateful_command_with_result,
|
||||
command_arguments_tuple_struct,
|
||||
async_simple_command_with_result,
|
||||
|
Loading…
Reference in New Issue
Block a user