Skip to content

Commit

Permalink
Improve: declare_raft_types allows the types in any order
Browse files Browse the repository at this point in the history
By rewriting the template expanding part with a `#[proc_macro]`
`expand!()` defined in `openraft_macros`, `declare_raft_types`
does not require the types in fixed order:

Example:

```
declare_raft_types!(All:
        D = (),
        NodeId = u64,
        R = (),
        Node = (),
```
  • Loading branch information
drmingdrmer committed Apr 14, 2024
1 parent 01bb4da commit e513b3b
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 113 deletions.
1 change: 1 addition & 0 deletions openraft/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ macro_rules! func_name {
// nn.split("::").last().unwrap_or_default()
}};
}
pub extern crate openraft_macros;

mod change_members;
mod config;
Expand Down
8 changes: 6 additions & 2 deletions openraft/src/raft/declare_raft_types_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ use crate::TokioRuntime;

declare_raft_types!(
All:
D = (),
R = (),
NodeId = u64,
Node = (),

/// This is AppData
D = (),
#[allow(dead_code)]
#[allow(dead_code)]
R = (),
Entry = crate::Entry<Self>,
SnapshotData = Cursor<Vec<u8>>,
AsyncRuntime = TokioRuntime,
Expand Down
133 changes: 22 additions & 111 deletions openraft/src/raft/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,20 @@ use crate::Vote;
/// Node = openraft::BasicNode,
/// Entry = openraft::Entry<TypeConfig>,
/// SnapshotData = Cursor<Vec<u8>>,
/// AsyncRuntime = openraft::TokioRuntime,
/// Responder = openraft::impls::OneshotResponder<TypeConfig>,
/// AsyncRuntime = openraft::TokioRuntime,
/// );
/// ```
///
/// **The types must be specified in the exact order**:
/// `D`, `R`, `NodeId`, `Node`, `Entry`, `SnapshotData`, `AsyncRuntime`, `Responder`
///
/// Types can be omitted, in which case the default type will be used.
/// The default values for each type are:
/// Types can be omitted, and the following default type will be used:
/// - `D`: `String`
/// - `R`: `String`
/// - `NodeId`: `u64`
/// - `Node`: `::openraft::impls::BasicNode`
/// - `Entry`: `::openraft::impls::Entry<Self>`
/// - `SnapshotData`: `Cursor<Vec<u8>>`
/// - `AsyncRuntime`: `::openraft::impls::TokioRuntime`
/// - `Responder`: `::openraft::impls::OneshotResponder<Self>`
/// - `AsyncRuntime`: `::openraft::impls::TokioRuntime`
///
/// For example, to declare with only `D` and `R` types:
/// ```ignore
Expand Down Expand Up @@ -150,111 +146,26 @@ macro_rules! declare_raft_types {
$visibility struct $id {}

impl $crate::RaftTypeConfig for $id {
$crate::declare_raft_types!(@F_0, $($(#[$inner])* $type_id = $type,)* @T);
}
};

// Add explicit type D
(@F_0, $(#[$meta:meta])* D=$t:ty, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
$(#[$meta])*
type D = $t;
$crate::declare_raft_types!(@F_1, $($(#[$inner])* $type_id = $type,)* @T);
};

// Add default type D
(@F_0, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
type D = String;
$crate::declare_raft_types!(@F_1, $($(#[$inner])* $type_id = $type,)* @T);
};
// `expand!(KEYED, ...)` ignores the duplicates.
// Thus by appending default types after user defined types,
// the absent user defined types are filled with default types.
$crate::openraft_macros::expand!(
KEYED,
(T, ATTR, V) => {ATTR type T = V;},
$(($type_id, $(#[$inner])*, $type),)*

// Default types:
(D , , String ),
(R , , String ),
(NodeId , , u64 ),
(Node , , $crate::impls::BasicNode ),
(Entry , , $crate::impls::Entry<Self> ),
(SnapshotData , , Cursor<Vec<u8>> ),
(Responder , , $crate::impls::OneshotResponder<Self> ),
(AsyncRuntime , , $crate::impls::TokioRuntime ),
);

(@F_1, $(#[$meta:meta])* R=$t:ty, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
$(#[$meta])*
type R = $t;
$crate::declare_raft_types!(@F_2, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_1, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
type R = String;
$crate::declare_raft_types!(@F_2, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_2, $(#[$meta:meta])* NodeId=$t:ty, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
$(#[$meta])*
type NodeId = $t;
$crate::declare_raft_types!(@F_3, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_2, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
type NodeId = u64;
$crate::declare_raft_types!(@F_3, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_3, $(#[$meta:meta])* Node=$t:ty, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
$(#[$meta])*
type Node = $t;
$crate::declare_raft_types!(@F_4, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_3, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
type Node = $crate::impls::BasicNode;
$crate::declare_raft_types!(@F_4, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_4, $(#[$meta:meta])* Entry=$t:ty, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
$(#[$meta])*
type Entry = $t;
$crate::declare_raft_types!(@F_5, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_4, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
type Entry = $crate::impls::Entry<Self>;
$crate::declare_raft_types!(@F_5, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_5, $(#[$meta:meta])* SnapshotData=$t:ty, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
$(#[$meta])*
type SnapshotData = $t;
$crate::declare_raft_types!(@F_6, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_5, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
type SnapshotData = Cursor<Vec<u8>>;
$crate::declare_raft_types!(@F_6, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_6, $(#[$meta:meta])* AsyncRuntime=$t:ty, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
$(#[$meta])*
type AsyncRuntime = $t;
$crate::declare_raft_types!(@F_7, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_6, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
type AsyncRuntime = $crate::impls::TokioRuntime;
$crate::declare_raft_types!(@F_7, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_7, $(#[$meta:meta])* Responder=$t:ty, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
$(#[$meta])*
type Responder = $t;
$crate::declare_raft_types!(@F_8, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_7, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T) => {
type Responder = $crate::impls::OneshotResponder<Self>;
$crate::declare_raft_types!(@F_8, $($(#[$inner])* $type_id = $type,)* @T);
};

(@F_8, @T ) => {};

// Match any non-captured items to raise compile error
(@F_8, $($(#[$inner:meta])* $type_id:ident = $type:ty,)* @T ) => {
compile_error!(
stringify!(
Type not in its expected position:
$($type_id=$type,)*
types must present in this order: D, R, NodeId, Node, Entry, SnapshotData, AsyncRuntime, Responder
)
);
}
};
}

Expand Down

0 comments on commit e513b3b

Please sign in to comment.