Skip to main content

client_task_enum

Attribute Macro client_task_enum 

Source
#[client_task_enum]
Expand description

§#[client_task_enum]

The #[client_task_enum] attribute is applied to an enum to delegate ClientTask related trait implementations to its variants. Each variant must wrap a struct that is a valid client task (often decorated with #[client_task])

This macro generates From implementations for each variant, allowing for easy conversion from a specific task struct to the enum. It also delegates methods from ClientTask, ClientTaskEncode, and ClientTaskDecode to the inner task.

client_task_enum also require error flag, specified the custom error type for RpcError<E: RpcErrCodec>

§#[action] on enum variants

As an alternative to defining the action inside the subtype, you can specify a static action directly on an enum variant using the #[action(...)] attribute. Only one action (numeric, or string literal, or numeric enum) is allowed per variant.

When #[action(...)] is used on a variant, the inner type does not need to define an action in this case, but if it does, the enum’s action will take precedence.

§Example:

use razor_stream::client::task::{ClientTask, ClientTaskCommon, ClientTaskAction, ClientTaskDone};
use razor_stream::error::RpcError;
use nix::errno::Errno;
use razor_stream_macros::{client_task, client_task_enum};
use serde_derive::{Deserialize, Serialize};
use crossfire::{mpsc, MTx};

#[derive(PartialEq, Debug)]
#[repr(u8)]
enum FileAction {
    Open = 1,
    Close = 2,
}

// Action can be specified in the FileTask enum
#[client_task(debug)]
pub struct FileOpenTask {
    #[field(common)]
    common: ClientTaskCommon,
    #[field(req)]
    req: String,
    #[field(resp)]
    resp: Option<()>,
    #[field(res)]
    res: Option<Result<(), RpcError<Errno>>>,
    #[field(noti)]
    noti: Option<MTx<mpsc::List<FileTask>>>,
}

// Action can be either with client_task
#[client_task(FileAction::Close, debug)]
pub struct FileCloseTask {
    #[field(common)]
    common: ClientTaskCommon,
    #[field(req)]
    req: (),
    #[field(resp)]
    resp: Option<()>,
    #[field(res)]
    res: Option<Result<(), RpcError<Errno>>>,
    #[field(noti)]
    noti: Option<MTx<mpsc::List<FileTask>>>,
}

#[client_task_enum(error=Errno)]
#[derive(Debug)]
pub enum FileTask {
    #[action(FileAction::Open)]
    Open(FileOpenTask),
    Close(FileCloseTask),
}

// Usage
let (tx, rx) = mpsc::unbounded_blocking();

// Test Open Task
let open_task = FileOpenTask {
    common: ClientTaskCommon::default(),
    req: "/path/to/file".to_string(),
    resp: None,
    res: None,
    noti: Some(tx.clone()),
};

let mut file_task: FileTask = open_task.into();
assert_eq!(file_task.get_action(), razor_stream::proto::RpcAction::Num(1));
file_task.set_ok();
file_task.done();

let received = rx.recv().unwrap();
assert!(matches!(received, FileTask::Open(_)));

// Test Close Task
let close_task = FileCloseTask {
    common: ClientTaskCommon::default(),
    req: (),
    resp: None,
    res: None,
    noti: Some(tx),
};

let mut file_task: FileTask = close_task.into();
assert_eq!(file_task.get_action(), razor_stream::proto::RpcAction::Num(2));
file_task.set_ok();
file_task.done();

let received = rx.recv().unwrap();
assert!(matches!(received, FileTask::Close(_)));