An open API service indexing awesome lists of open source software.

https://github.com/usagi/tia

tia; trait, impl accessors | automatic for Rust, proc-macro
https://github.com/usagi/tia

Last synced: about 2 months ago
JSON representation

tia; trait, impl accessors | automatic for Rust, proc-macro

Awesome Lists containing this project

README

        

[![github]](https://github.com/usagi/tia) [![crates-io]](https://crates.io/crates/tia) [![docs-rs]](https://docs.rs/tia)

[github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
[crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
[docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K

# tia; trait, impl accessors | automatic

This is a syntax sugar proc-macro crate for `trait`, `impl` accessors patterns. `tia` generate to an accessor `impl`s of an indivisual `trait`s for any `struct`|`enun`|`union`s.

## Features

- `tia` can be generate a `impl` codes automatically.
- Target types: `struct` | `enum` | `union`.
- Setting levels: {for all fields} | {per field}.
- `trait` supporting: Can be generate with multiple `trait`s. (See also the Example-3 in below.)
- Generative accessors: Getter-like {move, `Copy`, `&`, `&mut`}, Setter-like { move, `Copy`, `Clone`, `Into` }. (See also the Example-1,2 and Reference/tia directive section.)
- Useful +features: { `print`, `file-pretty`, `include`, `disable` }. (See also the Reference/features section.)
- Naming patters: { prefix, suffix, fullname }. (See also the Reference/tia directive section.)

## Example

### Example-1; The introduction of `tia`

It is minimal, very simple version. Without `trait`s complex.

```rust
use tia::Tia; // 1. use

#[derive(Tia)] // 2. derive
#[tia(rg)] // 3. tia directives
struct MyStruct
{
foo: i32,
bar: String
}

fn main()
{
let mys = MyStruct{ foo: 123, bar: "Hello".into() };
let foo = mys.get_foo(); // <-- 4. !! generated by tia automatically !!
let bar = mys.get_bar(); // <-- 5. !! generated by tia automatically !!
println!("foo={} bar={}", foo, bar );
}
```

`cargo run`, then you will get the output:

```sh
foo=123 bar=Hello
```

- (1,2) are preparing.
- (3) is tia directive for the struct-level.
- (4,5) are an automatic generated accessors by `tia`.

The automatic generated code is:

```rust
impl MyStruct
{
pub fn get_foo(&self) -> &i32
{
&self.foo
}

pub fn get_bar(&self) -> &String
{
&self.bar
}
}
```

It could be output to `src/.tia/MyStruct` if use `file-pretty` features in `Cargo.toml`:

```toml
[dependencies]
tia={ version="*", features=["file-pretty"] }
```

### Example-2; A little complex/practical usage

```rust
use tia::Tia; // use

#[derive(Tia, Debug, Default)] // derive
#[tia(rg, s)] // <-- tia directives, for all fields
struct MyStruct
{
#[tia(rmg)] // <-- #[tia(rg, s)] + #[tia(rmg)] => #[tia(rmg, s)]
foo: i32,
#[tia(rsi)] // <-- #[tia(rg, s)] + #[tia(rsi)] => #[tia(rg, rsi)]
bar: String,

baz: f64, // <-- #[tia(rg, s)]

#[tia(g)] // <-- #[tia(rg, s)] + #[tia(g)] => #[tia(g, s)] !! NOTE: Could be use for Copy-ables such as u8, but g pattern could not be use non-Copy-ables such as Vec
brabrabra: u8,

#[tia(gm)] // <-- #[tia(rg, s)] + #[tia(g)] => #[tia(gm, s)] !! WARNING: Could be move any types, but gm pattern will drop self
hogefuga: Vec
}

fn main()
{
let mut mys = MyStruct::default();

// rmg; reference-mut-getter
// with per-field level directive overwriting.
{
let foo = mys.get_foo(); // <-- &mut i32
*foo = 42;
dbg!(&foo);
dbg!(&mys);
}

// rsi: reference-setter-into
// with per-field level directive overwriting.
{
let a: &str = "Hello, ";
let b: String = String::from("tia.");
let c: &String = &b;

mys.set_bar(a); // &str
println!("a: mys.bar = {}", mys.get_bar());

mys.set_bar(b.clone()); // String; This effect move, thus the example is a -> c -> b
println!("b: mys.bar = {}", mys.get_bar());

mys.set_bar(c); // &String
println!("c: mys.bar = {}", mys.get_bar());
}

let x = mys.get_brabrabra(); // it will be Copy, mys will live
dbg!(x, &mys);

let y = mys.get_hogefuga(); // gm, get-move accessor will be drop mys
dbg!(y);
// mys was dropped, it could not be compile.
//dbg!(mys)
}
```

`cargo run`:

```rust
[src\main.rs:30] &foo = 42
[src\main.rs:31] &mys = MyStruct {
foo: 42,
bar: "",
baz: 0.0,
brabrabra: 0,
hogefuga: [],
}
a: mys.bar = Hello,
b: mys.bar = tia.
c: mys.bar = tia.
[src\main.rs:52] x = 0
[src\main.rs:52] &mys = MyStruct {
foo: 42,
bar: "tia.",
baz: 0.0,
brabrabra: 0,
hogefuga: [],
}
[src\main.rs:55] y = []
```

### Example-3; `trait` usage

```rust
use tia::Tia;

trait FooGettable{ fn get_foo(&self) -> T; }
trait Fruit{ fn get_bar(&self) -> &String; }
trait Sushi{ fn tuna(&self) -> u8; fn avocado(&mut self, v: u8); }

//include!(".tia/MyStruct.rs");
#[derive(Tia, Debug, Default)] // derive
struct MyStruct
{
#[tia(s, "FooGettable", g)]
foo: i32,
#[tia("Fruit",rg,"",rsi)]
bar: String,
#[tia("Sushi",g*="tuna",s*="avocado")] // <- `g` and `s`: Sushi trait
baz: u8
}

fn main()
{
let mut mys = MyStruct::default();
mys.set_foo(123);
mys.set_bar("meow");
let foo_gettable = &mys as &dyn FooGettable;
let fruit = &mys as &dyn Fruit;
println!("{}, {}", foo_gettable.get_foo(), fruit.get_bar() );
let sushi = &mut mys as &mut dyn Sushi;
sushi.avocado(32);
println!("{}", sushi.tuna());
}
```

Then `cargo run`:

```sh
123, meow
32
```

The generated code with `print`, `file` or `file-pretty` features:

```rust
impl FooGettable for MyStruct
{
fn get_foo(&self) -> i32
{
self.foo
}
}
impl MyStruct
{
pub fn set_bar>(&mut self, v: T)
{
self.bar = v.into();
}

pub fn set_foo(&mut self, v: i32)
{
self.foo = v;
}
}
impl Fruit for MyStruct
{
fn get_bar(&self) -> &String
{
&self.bar
}
}
impl Sushi for MyStruct
{
fn avocado(&mut self, v: u8)
{
self.baz = v;
}

fn tuna(&self) -> u8
{
self.baz
}
}
```

## Reference

### Usage

1. Preparing, add `tia="*"` in `[dependencies]` section of the project `Cargo.toml` file. ( Or I like `cargo add tia` via [cargo-edit][] )
- FYI: The `file-pretty` features is good tool for your debugging. Read the bottom section "features" if you want.
2. Use:
1. Write `#[derive(Tia)]` proc-macro on head of your struct|enum|union.
2. Write `#[tia(...)]` proc-macro below the `#[derive(Tia)]` (for struct|enum|union-level settings) or top of the specific fields.
- `...` is explanate in the next section "tia directives".

[cargo-edit]: https://github.com/killercup/cargo-edit

### tia directives

`tia`'s proc-macro can parse the pattern:

```
#[tia( $tia_directive_0, $tia_directive_1,$tia_directive_2, ... )]
```

And the `$tia_directive` pattern:

1. Accessor directive
- Accessors:
- Getter accessor like:
- `gm` => (`[g]et [m]ove`) **⚠ Move ⚠** pattern, it is NOT use for casually; like `fn (self) -> i32 { self.value }`
- `g` => (`[g]et`) For `Copy`-able values, for use a primitive types such as `u8`, `f32` or a `impl Copy`-ed types; like `return &self.value`.
- `rg` => (`[r]eference [g]et`) Return a reference `&` pattern. It can be use in casually for most situations.
- `rmg` => (`[r]eference [m]ut [g]et`) Return a reference mutable `&mut`. Sometimes useful, and sometimes so complex and difficult.
- Setter accelike:
- `s` => (`[s]et`) Raw value move pattern.
- `rs` => (`[r]eference [s]et`) Reference `&` pattern, for `Copy`-able types.
- `rsc` => (`[r]eference [s]et [c]lone`) `Clone` pattern, for `Clone`-able types such as `String`. This pattern require the same type for the input.
- `rsi` => (`[r]eference [s]et [i]nto`) `Into` pattern, for `Into`-able types such as `String`. This pattern could be type conversions. For eg, `&str`|`String`|`&String` and more types are input to `String` with this pattern.
- Naming policy
- Default ( eg. `g`, `rg` `rgi`) => Getters are same as the Prefix with "get", Setters are same as the Prefix with "set".
- `g="my_awesome_prefix"` => Prefix with specialized prefix-part string pattern. It will be generate `fn my_awesome_prefix_xxxx` for `xxxx` field symbol.
- `g+="my_awesome_suffix"` => Suffix with specialized suffix-part string pattern. It will be generate `fn xxxx_my_awesome_suffix` for `xxxx` field symbol.
- `g*="my_awesome_fullname"` => Fullname pattern. It will be generate `fn my_awesome_fullname` for a field.
2. Trait directive
- Default ( no trait directives ) => It will be generate `impl for MyStruct` codes for a fields.
- `"TraitSymbol"` => It will be generate `impl TraitSymbol for MyStruct` codes for a fields that appear in the after of this directive.
- `""` => It will be generate `impl for MyStruct` codes for a fields that appear in the after of this directive.

### features

#### `disable`

Usage example:

```toml
[dependencies]
tia={ version="*", features=["disable"] }
```

- `tia` will be output nothing.
- But `tia` is not removed, thus it allow the `#[derive(Tia)]` and `#[tia(...)]` proc-macros with no effects.

#### `print`

Usage example:

```toml
[dependencies]
tia={ version="*", features=["print"] }
```

- `tia` will be output the generated code to STDERR.
- But it is difficully to human eyes, thus `file-pretty` is better for human eyes.

#### `file`|`file-pretty`

Usage example:

```toml
[dependencies]
tia={ version="*", features=["file-pretty"] }
```

- `tia` will be output/update the generated code to the file such as `src/.tia/MyStruct.rs`.
- This file is not for use in build, but if you want check the generated code with your eyes then it helpful.

What's the difference of `file` and `file-pretty`:

- `file` will be output the raw generated code. It is very compressed.
- `file-pretty` will be output the raw generated code, and then apply `rustfmt` automatically.
- note: this feature reqwire the `rustfmt` command in your development environment. (It is not a lib crate dependency.)

#### `include`|`include-pretty`|`include-force`

Usage example:

```toml
[dependencies]
tia={ version="*", features=["include-pretty"] }
```

`tia` will be:

1. Generate codes if not exists.
2. Generate `include!(...)` macro such as `include!("src/.tia/MyStruct")` instead.

What's the difference of `include`, `include-pretty` and `include-force`:

- `include` will be generate (=`file`) code if the generated code is not found.
- `include-pretty` will be generate and prettify (=`file-pretty`) if the generated code is not found.
- `include-force` will not be generate if the generated code is not found, maybe build will stop with an error(s).

## Note

`tia` provide a useful syntax sugar, it will helpful if you should impl many interface-like specifications. For eg, something designed for object-oriented paradigm mainly languages such as C#, Java, C++, or complex data definition based by UML such as XMLSchema. But, it is just a syntax sugar. Please do not overdose `tia` unnecessarily.

## LICENSE

- [MIT](LICENSE.md)

## Contributor

- [@yrashk](https://github.com/yrashk)

Thank you!😍

## Author

- USAGI.NETWORK / Usagi Ito