Crates.io | fieldx_plus |
lib.rs | fieldx_plus |
version | |
source | src |
created_at | 2024-10-03 23:50:35.703002 |
updated_at | 2024-12-05 22:29:11.323265 |
description | Design patterns built on top of fieldx crate |
homepage | |
repository | https://github.com/vrurg/fieldx_plus.git |
max_upload_size | |
id | 1395817 |
Cargo.toml error: | TOML parse error at line 22, column 1 | 22 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include` |
size | 0 |
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
takes and
adds of couple of its own. But be aware that it overrides some of fxstruct
arguments:
app
or parent
fxstruct(rc)
is enforcedagent
or child
it sets fxstruct(no_new, builder)
; setting additional parameters with the builder
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 produce app
/parent
methods that return ErrorType
; 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 on self
. <expr>
can either be just method name
or something like map_to_err("argument", 42)
in which case the map_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.
Licensed under the BSD 3-Clause License.