[](https://github.com/dekirisu/strung)
[](https://crates.io/crates/strung)
[](https://docs.rs/strung)
[](https://crates.io/crates/strung)
[](https://discord.gg/kevWvBuPFg)
String formatter/builder with easy access of struct fields, which implement the *Display* trait.
If they do not, they can be marked to be ignored.
# Usage
Here's most you have to know!
```rust
use strung::prelude::*; // import everything from prelude
fn main(){
// create structs - defined below cause instant action!
let NAMED = Test {num: 1, name: "st"};
let TUPLE = TestTup (1, "st");
let CUSTOM = TestCustom {num: 1, nop: NoDsply};
// most general - you'll probably mostly use this! - using {field_name}
let text = NAMED.strung("{num}{name}");
assert_eq!(&text,"1st");
// also works with String, just reference it
let s: String = "{num}{name}".into();
let text = NAMED.strung(&s);
assert_eq!(&text,"1st");
// it will always replace every occurrence
let text = NAMED.strung("{num}{num}th < {num}{name}");
assert_eq!(&text,"11th < 1st");
// for tuple structs, use the fields index number, instead of the name
let text = TUPLE.strung("{0}{1}");
assert_eq!(&text,"1st");
// the [strung] function will change if you set custom pre/postfix - see TestCustom below
let text = CUSTOM.strung("%num%st");
assert_eq!(&text,"1st");
// there are different presets, so you can still use {field_name} using [strung_curly]
let text = CUSTOM.strung_curly("{num}st");
assert_eq!(&text,"1st");
// note: {nop} is not available, cause it's ignored - see TestCustom below
let text = CUSTOM.strung_curly("{num}st {nop}");
assert_eq!(&text,"1st {nop}");
// [strung_dollar] for $field_name
let text = NAMED.strung_dollar("$num$name");
assert_eq!(&text,"1st");
// [strung_dollry] for ${field_name}
let text = NAMED.strung_dollry("${num}${name}");
assert_eq!(&text,"1st");
// [strung_hashtag] for #field_name
let text = NAMED.strung_hashtag("#num#name");
assert_eq!(&text,"1st");
// [strung_angle] for #field_name
let text = NAMED.strung_angle("<num><name>");
assert_eq!(&text,"1st");
// most flexible - inline setting via [strung_dynamic] - a bit less efficient
let text = NAMED.strung_dynamic("<",">","<num><name>");
assert_eq!(&text,"1st");
// also flexible - global static variables, you can easily change ...
strung::config::static_global("+","+");
let text = NAMED.strung_static("+num++name+");
assert_eq!(&text,"1st");
// ... whenever you want, but usually you'll just need it once at the start of main()
strung::config::static_global("[","]");
let text = NAMED.strung_static("[num][name]");
assert_eq!(&text,"1st");
// [strung_hashtag] and [strung_dollar] also enable cascading
let CASCADE = TestCascade {tup: TestTup(2,"nd")};
let text = CASCADE.strung_dollar("$tup.0$tup.1");
assert_eq!(&text,"2nd");
}
// named struct
#[derive(Strung)] // easy derive
struct Test {
num: u32,
name: &'static str,
}
// tuple struct
#[derive(Strung)] // easy derive
struct TestTup(u32,&'static str);
// custom pre/postfix per struct + ignore
#[derive(Strung)] // easy derive
#[strung("%","%")] // custom pre/postfix!
struct TestCustom {
num: u32,
// ignore: makes this field unavailable
// this would fail w/o the ignore, cause no [Display]!
// other usage: gain a lil more performance
#[strung(ignore)] nop: NoDsply
}
// custom pre/postfix per struct + ignore
#[derive(Strung)] // easy derive
struct TestCascade {
// cascade: makes the fields of another Strung available
// the ignore only affects the the struct itself, not its fields
// and this would fail w/o it cause it doesn't implement it!
#[strung(cascade,ignore)]
tup: TestTup
}
// struct with no Display trait
struct NoDsply;
```
# About Statics
Prelude imports two static variables [config::STRUNG_PRE] and [config::STRUNG_POST], which can be used
to set the prefix and postfix as a configuration. [Strung::strung_static] uses anything called STRUNG_PRE or STRUNG_POST
on the file.
[config::static_global] changes these variables, as you saw in the walkthrough, there's another method of
changing it per file. It's not included in the walkthrough cause it shadows these variables, it's a macro called [config::static_on_file].
📝 Note: This will <strong>maybe</strong> change in future, so these variables dont have to always be imported.
But: here's how it can be used for now:
```rust
use strung::prelude::*; // Import everything from prelude
strung::config::static_on_file!("[","]"); // 🌱 Shadow static pre/postfix for this file.
#[derive(Strung)] // You know the drill :)
struct Test {
text: &'static str,
num: u32
}
fn main(){
let test = Test { // Create struct as usual
text: "5k",
num: 5000
};
let text = test.strung_static("[text]=[num]"); // 🌱 Use whatever you've set above
assert_eq!(&text,"5k=5000");
}
```
# Ignore fields
Sometimes you wanna ignore certain fields - e.g. in these scenarios:
- Get even moar efficiency 📈
- A field-type doesn't implement [std::fmt::Display]
This can be done with the #[strung(ignore)] attribute:
```rust
use strung::prelude::*;
struct CustomField (u32);
#[derive(Strung)]
struct Test {
num: u32,
#[strung(ignore)] nope: CustomField }
#[derive(Strung)]
struct TestTup (
u32,
#[strung(ignore)] CustomField, &'static str
);
fn main(){
let test = Test { num: 1,
nope: CustomField(0), };
let text = test.strung("Number {num} {nope}"); assert_eq!(&text,"Number 1 {nope}");
let test = TestTup(1,CustomField(0),":)"); let text = test.strung("Number {0} {1} {2}"); assert_eq!(&text,"Number 1 {1} :)");
}
```
# ❗ Experimental: Cascading ❗
There's also the possibility of cascading. e.g.: `$field.0.num`, it's experimentally implemented for [Strung::strung_dollar] and [Strung::strung_hashtag] at the moment,
cause it was the easiest to do. 🦀
For this to work, the field-type has to derive [Strung] via derive macro and mark it with the `#[strung(cascade)]` attribute:
```rust
use strung::prelude::*;
// #[strung(ignore)] just because none of them are implementing Display!
#[derive(Strung)] struct A {#[strung(cascade,ignore)]field:B}
#[derive(Strung)] struct B (u32,#[strung(cascade,ignore)]C);
#[derive(Strung)] struct C {#[strung(cascade,ignore)]field:D,num:u32}
#[derive(Strung)] struct D (#[strung(cascade,ignore)]E);
#[derive(Strung)] struct E {num:u32}
fn main(){
let test = A{
field: B(500,C{
num: 123,
field: D(E{
num: 623
})
})
};
let text = test.strung_dollar(
"Hello, $field.0 + $field.1.num = $field.1.field.0.num"
);
assert_eq!(&text,"Hello, 500 + 123 = 623");
let text = test.strung_hashtag(
"Hello, #field.0 + #field.1.num = #field.1.field.0.num"
);
assert_eq!(&text,"Hello, 500 + 123 = 623");
}
```
#### License
<sup>
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
</sup>
<br>
<sub>
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.
</sub>