3 releases
0.1.2 | Oct 20, 2024 |
---|---|
0.1.1 | Oct 9, 2024 |
0.1.0 | Oct 3, 2024 |
#2290 in Procedural macros
410 downloads per month
Used in fieldx_plus
32KB
662 lines
fieldx_plus v0.1.2
This crate is intended for implementing some design patterns, based on fieldx
crate. At the moment it is only Application/Agent and Parent/Child patterns. Both are basically the same thing
essentially where Application/Parent is a reference counted object and agents/children hold references to it. The
difference is in children accessor method names which are app
and parent
, correspondingly.
Unfortunately, lack of time doesn't allow me to create comprehensive documentation for this crate. Consider the tests as the starting points. But here is, briefly, an idea of how it looks:
use fieldx_plus::{fx_plus, agent_build};
use thiserror::Error;
#[derive(Error, Debug)]
enum AppError {
#[error("{0}")]
AdHoc(String),
#[error("Application object is unexpectedly gone")]
AppIsGone
}
#[fx_plus(app, sync)]
struct Application {
#[fieldx(lazy, get)]
service: NetService,
}
impl Application {
fn build_service(&self) -> NetService {
agent_build!(
self, NetService {
port: 4242,
name: "app service",
}
).unwrap()
}
pub fn config(&self, key: &str) -> u32 {
42
}
pub fn run() {
let app = Application::new();
app.service().launch().expect("Something went wrong...");
}
}
#[fx_plus(agent(Application, unwrap(error(AppError, AppError::AppIsGone))), sync)]
struct NetService {
port: u16,
#[fieldx(into, get)]
name: String,
}
impl NetService {
pub fn launch(&self) -> Result<(), AppError> {
let app = self.app()?;
let cfg = app.config("foo");
println!("Launching '{}' service.", self.name());
Ok(())
}
}
fn main() {
Application::run();
}
Here is a quick breakdown for it:
fx_plus
is an extender to fieldx::fxstruct
attribute. As such, it takes all the arguments, fxstruct
take and
adds of couple of its own. But be aware that it overrides some of fxstruct
argument:
- with
app
orparent
fxstruct(rc)
is enforced - with
agent
orchild
it setsfxstruct(no_new, builder)
; setting additional parameters with thebuilder
are allowed, though:fx_plus(child, builder(into))
With any of the four serde
gets disabled if serde
feature is enabled.
Since application/parent struct is always rc
there is a chance that its reference counter can drop to 0 while an
agent/child with weak reference attempts to call .app()
or .parent()
, which internally attempt to upgrade the
reference. agent(unwrap)
argument controls how this situation is handled:
arguments:
child(unwrap)
results in simple.unwrap()
applied the upgrade callunwrap(expect("Error message")
commands to use.expect("Error message")
; with this and the above variant we always get just the app/parent objectunwrap(error(ErrorType, <expression>))
would produceapp
/parent
methods that returnErrorType
; the particular value returned depends on the<expression>
. Say,ErrorType::ParentIsGone
can be used to return a specific error codeunwrap(map(ErrorType, <expr>))
can be used to invoke a method onself
.<expr>
can either be just method name or something likemap_to_err("argument", 42)
in which case themap_to_err
method will get the arguments specified.
Helper macros agent_build
, agent_builder
, child_build
, and child_builder
are wrappers around builder
pattern. I.e. agent_build!(self.app(), Agent { foo: 42, bar: "baz" })
is actually a shortcut for
Agent::builder().app(self.app()).foo(42).bar("baz").build()
. agent_builder
is the same but without the final
build()
call.
License
Licensed under the BSD 3-Clause License.
Dependencies
~1.2–6.5MB
~40K SLoC