| Crates.io | flmacro |
| lib.rs | flmacro |
| version | 0.9.2 |
| created_at | 2025-02-25 07:11:00.769744+00 |
| updated_at | 2025-03-17 05:52:29.377052+00 |
| description | Macros for fledger |
| homepage | https://fledg.re |
| repository | https://github.com/ineiti/fledger |
| max_upload_size | |
| id | 1568786 |
| size | 21,424 |
Macros for the use in fledger.
This holds the macro for defining an async_trait either with or without the
Send trait.
You can use it like this:
#[platform_async_trait()]
impl SubsystemHandler<Message> for SomeBroker {
async fn messages(&mut self, _: Vec<Message>) -> Vec<Message> {
todo!();
}
}
Depending on wasm or unix, it will either remove or keep the Send trait.
This allows to use tuple struct, or a newtype struct, based on U256, to export
all methods from U256.
Instead of using a type definition, which is not unique and can be replaced by any
of the other types, tuple structs allow for more type safety.
You can use it like this:
#[derive(AsU256)]
struct MyID(U256);
And now you can have MyID::rnd() and all the other methods from U256.
To store configuration and other data in different version, you can use this derive macro:
use bytes::Bytes;
use flmacro::VersionedSerde;
use serde::{Deserialize, Serialize};
use serde_with::{base64::Base64, serde_as};
#[serde_as]
#[derive(VersionedSerde, Clone, PartialEq, Debug)]
#[versions = "[ConfigV1, ConfigV2]"]
struct Config {
#[serde_as(as = "Base64")]
name3: Bytes,
}
impl From<ConfigV2> for Config {
fn from(value: ConfigV2) -> Self {
Self { name3: value.name2 }
}
}
#[derive(Serialize, Deserialize, Clone)]
struct ConfigV2 {
name2: Bytes,
}
impl From<ConfigV1> for ConfigV2 {
fn from(value: ConfigV1) -> Self {
Self { name2: value.name }
}
}
#[derive(Serialize, Deserialize, Clone)]
struct ConfigV1 {
name: Bytes,
}
It will do the following:
struct Config as struct ConfigV3 with appropriate FROM implementationsConfigVersion enum with all configs in itserde::Serialize and serde::Deserialize on Config which will
Config in the ConfigVersionConfigVersion, orConfigVersion and convert it to ConfigThis allows you to use any serde implementation to store any version of your structure, and retrieve always the latest version:
#[test]
fn test_config() -> anyhow::Result<()> {
// Simulate the storage of an old configuration.
let v1 = ConfigV1 { name: "123".into() };
let cv1 = ConfigVersion::V1(v1);
let c: Config = cv1.clone().into();
let cv1_str = serde_yaml::to_string(&cv1)?;
// Now the old version is recovered, and automatically converted
// to the latest version.
let c_recover: Config = serde_yaml::from_str(&cv1_str)?;
assert_eq!(c_recover, cv1.into());
// Storing and retrieving the latest version is always
// done using the original struct, `Config` in this case.
let c_str = serde_yaml::to_string(&c)?;
let c_recover = serde_yaml::from_str(&c_str)?;
assert_eq!(c, c_recover);
Ok(())
}
To allow usage of serde_as, the VersionedSerde also defines the serde attribute.
However, VersionedSerde does not use it itself.
When you start with a new configuration structure, the versions can be omitted:
#[derive(VersionedSerde, Clone)]
struct NewStruct {
field: String
}
When converting this using serde, it will store it as V1.
So whenever you create a new version, you can add it with
a converter to the latest structure:
#[derive(VersionedSerde, Clone)]
#[versions = "[NewStructV1]"]
struct NewStruct {
field: String,
other: String
}
impl From<NewStructV1> for NewStruct {
fn from(value: NewStructV1) -> Self {
Self {
field: value.field,
other: "default".into(),
}
}
}
#[derive(Serialize, Deserialize, Clone)]
struct NewStructV1 {
field: String
}
This macro does two things:
Box at the end, and
it adds + Send for non-wasm targets+ Send three characters from the end of the type in
rust-macro-formatSo the following
#[target_send]
trait Something<T>{}
#[target_send]
type SomethingElse<T> = Box<dyn SomethingMore<T>>;
Will be translated to:
trait Something<T>{}
type SomethingBox<T> = Box<dyn Something<T> $SEND>
type SomethingElse<T> = Box<dyn SomethingMore<T> $SEND>;
with $SEND either an empty string for wasm targets, or + Send for non-wasm targets.
Specifically the handling of the type is very ugly, as it converts the type to a string,
adds conditionally + Send three characters from the end, and parses the resulting string.
Kids, don't do this at home...
When using #[tokio::test] the stack is sometimes too small, for example in the
flmacro::test::webpage test.
This is where the test_async_stack macro comes in, which sets a bigger stack size
and also adds more threads.
You can use it like this:
#[test_async_stack(stack_size = 10 * 1024 * 1024, worker_threads = 8)]
async fn page_full() -> anyhow::Result<()> {
Ok(())
}
If the chose values work for you, they can be omitted.