Skip to content

Easy access of struct fields in strings using different/custom pre/postfix: "Hello, {field}" in rust

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

dekirisu/strung

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 Cannot retrieve latest commit at this time.

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHub Version Docs License Discord

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!

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");

    // 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 maybe change in future, so these variables dont have to always be imported.

But: here's how it can be used for now:

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:
use strung::prelude::*;                     // Import everything from prelude

struct CustomField (u32);                   // 🌱 A struct, not impl Display

#[derive(Strung)]
struct Test {
    num: u32,
    #[strung(ignore)] nope: CustomField     // 🌱 Would fail without the attribute!
}

#[derive(Strung)]
struct TestTup (
    u32, 
    #[strung(ignore)] CustomField,          // 🌱 Would fail without the attribute!
    &'static str
); 

fn main(){
    /* ------------------------------ Named Fields ------------------------------ */
    let test = Test {                               // Create struct as usual
        num: 1,
        nope: CustomField(0),                       // 🌱
    };
    let text = test.strung("Number {num} {nope}");  // 🌱 {nope} not available!
    assert_eq!(&text,"Number 1 {nope}");

    /* ------------------------- Unnamed Fields (Tuple) ------------------------- */
    let test = TestTup(1,CustomField(0),":)");      // Create struct as usual
    let text = test.strung("Number {0} {1} {2}");   // 🌱 {1} not available!
    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:

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

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
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.

About

Easy access of struct fields in strings using different/custom pre/postfix: "Hello, {field}" in rust

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published

Languages