Skip to main content

DynCommand

Struct DynCommand 

Source
pub struct DynCommand<Req, Res, F> { /* private fields */ }
Expand description

A runtime-constructed Command. Use this when the command id or schema is only known at runtime (plugin runtimes, FFI, scripting hosts).

§Example — dynamic id with Value payloads

use coralstack_cmd_ipc::prelude::*;
use serde_json::{json, Value};

let cmd = DynCommand::new("plugin.say_hi", |_req: Value| async move {
    Ok(json!({ "greeting": "hello" }))
});
registry.register_command(cmd).await?;

§Example — dynamic id with typed payloads

#[derive(serde::Deserialize)]
struct AddReq { a: i64, b: i64 }

let cmd = DynCommand::new(runtime_id, |req: AddReq| async move {
    Ok(req.a + req.b)
})
.description("Runtime-registered adder");
registry.register_command(cmd).await?;

Implementations§

Source§

impl<Req, Res, F, Fut> DynCommand<Req, Res, F>
where Req: DeserializeOwned + Send + 'static, Res: Serialize + Send + 'static, F: Fn(Req) -> Fut + Send + Sync + 'static, Fut: Future<Output = Result<Res, CommandError>> + Send + 'static,

Source

pub fn new(id: impl Into<String>, handler: F) -> Self

Build a new dynamic command. The request/response types are inferred from the handler’s signature; annotate them if type inference needs help (commonly |req: Value| for fully dynamic payloads).

Source

pub fn description(self, description: impl Into<String>) -> Self

Attach a human-readable description, surfaced via Command::description and forwarded to MCP/tooling consumers.

Source

pub fn schema(self, schema: CommandSchema) -> Self

Attach a full CommandSchema (both request + response slots) advertised on the wire via register.command.request. Omit to register without a schema (peers will fall back to permissive validation).

Source

pub fn request_schema(self, schema: Value) -> Self

Attach only the request schema. Convenient when your runtime introspection knows the argument shape but not the return.

Source

pub fn response_schema(self, schema: Value) -> Self

Attach only the response schema.

Source§

impl DynCommand<Value, Value, BoxedHandler>

Source

pub fn boxed<F, Fut>(id: impl Into<String>, handler: F) -> BoxedDynCommand
where F: Fn(Value) -> Fut + Send + Sync + 'static, Fut: Future<Output = Result<Value, CommandError>> + Send + 'static,

Construct a BoxedDynCommand from any async closure producing a Result<Value, CommandError>. The handler’s future is boxed so the resulting command has a single concrete type, making it suitable for heterogeneous collections.

use coralstack_cmd_ipc::prelude::*;
use coralstack_cmd_ipc::BoxedDynCommand;
use serde_json::{json, Value};

let cmd: BoxedDynCommand = DynCommand::boxed("plugin.hello", |req| async move {
    Ok(json!({ "you_sent": req }))
});
registry.register_command(cmd).await?;

Trait Implementations§

Source§

impl<Req, Res, F, Fut> Command for DynCommand<Req, Res, F>
where Req: DeserializeOwned + Send + Sync + 'static, Res: Serialize + Send + Sync + 'static, F: Fn(Req) -> Fut + Send + Sync + 'static, Fut: Future<Output = Result<Res, CommandError>> + Send + 'static,

Source§

const ID: &'static str = ""

Compile-time identifier for typed commands. Ignored when a command overrides id to return a runtime string (as DynCommand does). Read more
Source§

type Request = Req

Source§

type Response = Res

Source§

fn id(&self) -> &str

Instance-level identifier. Defaults to ID. DynCommand overrides this to return a runtime-owned id.
Source§

fn description(&self) -> Option<&str>

Instance-level description. Defaults to DESCRIPTION.
Source§

fn schema(&self) -> Option<CommandSchema>

Wire-level JSON Schema for this command. Defaults to None. The #[command] macro overrides this with a schema generated from Request and Response via schemars.
Source§

fn handle( &self, request: Req, ) -> impl Future<Output = Result<Res, CommandError>> + Send

Handles a single invocation.
Source§

const DESCRIPTION: Option<&'static str> = None

Optional compile-time description. Ignored when description is overridden.

Auto Trait Implementations§

§

impl<Req, Res, F> Freeze for DynCommand<Req, Res, F>
where F: Freeze,

§

impl<Req, Res, F> RefUnwindSafe for DynCommand<Req, Res, F>
where F: RefUnwindSafe,

§

impl<Req, Res, F> Send for DynCommand<Req, Res, F>
where F: Send,

§

impl<Req, Res, F> Sync for DynCommand<Req, Res, F>
where F: Sync,

§

impl<Req, Res, F> Unpin for DynCommand<Req, Res, F>
where F: Unpin,

§

impl<Req, Res, F> UnsafeUnpin for DynCommand<Req, Res, F>
where F: UnsafeUnpin,

§

impl<Req, Res, F> UnwindSafe for DynCommand<Req, Res, F>
where F: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.