Documentation
# ty(pe)f(ormat)ling

easier implementations of the formatting traits, supporting structs, enums

```
# use {::tyfling::{display, lower_hex}, ::core::fmt::{Display, LowerHex}};
#[display("foo: {f0}")]
#[lower_hex("foo: {f0:x}")]
struct Foo<#[display] #[lower_hex] T>(T);

println!("{}", Foo(4)); // foo: 4
println!("{:x}", Foo(0x57e11a)); // foo: 57e11a
```

## provides

9 attribute proc macros

- `binary`, implementing the `Binary` trait
- `debug`, implementing the `Debug` trait
- `display`, implementing the `Display` trait
- `lower_exp`, implementing the `LowerExp` trait
- `lower_hex`, implementing the `LowerHex` trait
- `octal`, implementing the `Octal` trait
- `pointer`, implementing the `Pointer` trait
- `upper_exp`, implementing the `UpperExp` trait
- `upper_hex`, implementing the `UpperHex` trait

## usage

### struct

attach the attribute to the struct, and pass in formatting info

### enum

attach the attribute to the enum and each variant, the enum's attribute should be empty, while the variants should have their individual formatting info

### syntax

`display` is used as an example, but the functionality is identical for all of the attributes

- `#[display("formatting string")]` formats without any variation, just a plain format string
- `#[display("fmt string that references {f0} tuple fields")]` for tuple structs and tuple enum variants, their fields can be accessed as the `f{n}` local variables (eg: `f0`, `f1`, etc)
- `#[display("fmt string that references {n} struct fields")]` for named field structs and named field enum variants, their fields are available verbatim
- `#[display("fmt string doing {} calculations {how_often}", how_much = if 42 == ~42 { "a few" } else { "at least 1" }, how_often = "uhh, once?")]` format strings can have arguments like normal format strings
- `#[display(.1)]` delegate to a tuple field of the [struct,enum variant] equivalent to `"{1}"` (or whatever format specifier is used for a given trait) but more readable
- `#[display(.some_field)]` delegate to a named field of the [struct,enum variant] equivalent to `"{some_field}"`

if any of the format strings for a type formats a generic parameter that isnt already constrained to the given trait, apply the attribute to the generic type to constrain just the impl:

```rust
# use {::tyfling::display, ::core::fmt::Display};
// ok, because the parameter is constrained to Display
#[display("foo: {f0}")]
struct Foo<T: Display>(T);

// ok, because the parameter is formatted
#[display("bar: ignoring the field")]
struct Bar<T>(T);
```

```compile_fail
# use {::tyfling::display, ::core::fmt::Display};
// NOT ok, because there's no bound/attribute, and the parameter is used
#[display("bar: {f0}")]
struct Baz<T>(T);
```

```rust
# use {::tyfling::display, ::core::fmt::Display};
// ok, because attribute constrains the impl
// does not constrain the struct, only the impl
#[display("qux: {f0}")]
struct Qux<#[display] T>(T);
```

## example

```rust
# use ::tyfling::display;

// set a format string and implement Display
#[display("diagnostic (from {source_file_name}): {kind}")]
struct Diagnostic</* since the format string uses a generic type, ensure that the impl is constrained to T: Display */ #[display] O> {
	kind: DiagnosticKind<O>,
	source_file_name: &'static str,
}

#[display]
enum DiagnosticKind<#[display] O> {
	#[display("forgot macro bang (at bytes {} to {}): {code}", span.start, span.end)]
	ForgotMacro {
		code: &'static str,
		span: ::core::ops::Range<usize>,
	},
	// no additional context to add, delegate to the indexed field
	#[display(.0)]
	Message(String),
	// unknown context, just delegate to the error fields
	#[display(.error)]
	OtherError {
		error: O,
		fatal: bool,
	},
}

#[display("displayable!")]
struct Displayable;

# fn main() {
assert_eq!(format!("{}", Diagnostic::<Displayable> {
	kind: DiagnosticKind::ForgotMacro {
		code: "fn main() { println(\"hello world!\"); }",
		span: 12..20,
	},
	source_file_name: "src/lib.rs",
}), "diagnostic (from src/lib.rs): forgot macro bang (at bytes 12 to 20): fn main() { println(\"hello world!\"); }");
assert_eq!(format!("{}", Diagnostic::<Displayable> {
	kind: DiagnosticKind::OtherError {
		error: Displayable,
		fatal: false,
	},
	source_file_name: "src/lib.rs",
}), "diagnostic (from src/lib.rs): displayable!");
# }
```

```compile_fail
# use ::tyfling::display;
# 
# // set a format string and implement Display
# #[display("diagnostic (from {source_file_name}): {kind}")]
# struct Diagnostic</* since the format string uses a generic type, ensure that the impl is constrained to T: Display */ #[display] O> {
# 	kind: DiagnosticKind<O>,
# 	source_file_name: &'static str,
# }
# 
# #[display]
# enum DiagnosticKind<#[display] O> {
# 	#[display("forgot macro bang (at bytes {} to {}): {code}", span.start, span.end)]
# 	ForgotMacro {
# 		code: &'static str,
# 		span: ::core::ops::Range<usize>,
# 	},
# 	// no additional context to add, delegate to the indexed field
# 	#[display(.0)]
# 	Message(String),
# 	// unknown context, just delegate to the error fields
# 	#[display(.error)]
# 	OtherError {
# 		error: O,
# 		fatal: bool,
# 	},
# }
struct NotDisplayable;

# fn main() {
//! compile error, cannot Display, because NotDisplayable is not displayable
assert_eq!(format!("{}", Diagnostic::<NotDisplayable> {
	kind: DiagnosticKind::OtherError {
		error: NotDisplayable,
		fatal: true,
	},
	source_file_name: "src/lib.rs",
}), "");
# }
```