Skip to main content

client_task

Attribute Macro client_task 

Source
#[client_task]
Expand description

§#[client_task]

The #[client_task] attribute macro is used on a struct to designate it as a client-side RPC task. It simplifies implementation by generating boilerplate code for several traits.

The macro always generates:

  • Deref and DerefMut to the field marked #[field(common)].
  • ClientTaskEncode for the #[field(req)] and #[field(req_blob)] fields.
  • ClientTaskDecode for the #[field(resp)] and #[field(resp_blob)] fields.

The macro can also conditionally generate:

  • ClientTaskAction: Generated if a static action is provided (e.g., #[client_task(1)]) or if a field is marked #[field(action)].
  • ClientTaskDone: Generated if both #[field(res)] and #[field(noti)] are present. If not generated, you must implement this trait manually.

§Field Attributes:

  • #[field(common)]: (Mandatory) Marks a field that holds common task information (e.g., ClientTaskCommon). Allows direct access to members like seq via Deref.

  • #[field(action)]: Specifies a field that dynamically provides the RPC action. Mutually exclusive with a static action in #[client_task(...).

  • #[field(req)]: (Mandatory) Designates the field for the request payload.

  • #[field(resp)]: (Mandatory) Designates the field for the response payload, which must be an Option<T>.

  • #[field(req_blob)]: (Optional) Marks a field for an optional request blob. Must implement AsRef<[u8]>.

  • #[field(resp_blob)]: (Optional) Marks a field for an optional response blob. Must be Option<T> where T implements razor_stream::buffer::AllocateBuf.

  • #[field(res)]: (Optional) When used with #[field(noti)], triggers automatic ClientTaskDone implementation. Must be of type Option<Result<(), RpcError<E>>> where E implements razor_stream::error::RpcErrCodec. Stores the final result of the task.

  • #[field(noti)]: (Optional) When used with #[field(res)], triggers automatic ClientTaskDone implementation. Must be an Option wrapping a crossfire list channel MTx sender (e.g., Option<crossfire::MTx<crossfire::mpsc::List<ParentTask>>>) to notify of task completion. where the task has impl Into as ParentTask extracted with crossfire::flavor::Queue::Item

§Example of Automatic ClientTaskDone

use razor_stream::error::RpcError;
use nix::errno::Errno;
use razor_stream_macros::client_task;
use serde_derive::{Deserialize, Serialize};
use crossfire::{mpsc, MTx};
use razor_stream::client::task::*;

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct FileReadReq {
    pub path: String,
    pub offset: u64,
    pub len: u64,
}

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct FileReadResp {
    pub bytes_read: u64,
}

// A task with automatic `ClientTaskDone` implementation.
#[client_task(1, debug)]
pub struct FileReadTask {
    #[field(common)]
    common: ClientTaskCommon,
    #[field(req)]
    req: FileReadReq,
    #[field(resp)]
    resp: Option<FileReadResp>,
    #[field(res)]
    res: Option<Result<(), RpcError<Errno>>>,
    #[field(noti)]
    noti: Option<MTx<mpsc::List<Self>>>,
}

// Usage
let (tx, rx) = mpsc::unbounded_blocking::<FileReadTask>();
let mut task = FileReadTask {
    common: ClientTaskCommon { seq: 1, ..Default::default() },
    req: FileReadReq { path: "/path/to/file".to_string(), offset: 0, len: 1024 },
    resp: None,
    res: None,
    noti: Some(tx),
};

task.set_ok();
task.done();

let completed_task = rx.recv().unwrap();
assert_eq!(completed_task.common.seq, 1);
assert!(completed_task.res.is_some() && completed_task.res.as_ref().unwrap().is_ok());