describer 0.3.1

Struct describing helper
Documentation
# Describer

This crate provides human-readable type descriptions through the `Describer` trait and its derive macro.

## Overview

`describer` allows you to generate string representations of Rust types at compile time. This is useful for documentation, debugging, API introspection, code generation, and understanding complex type hierarchies.

### Breaking Changes
- `v0.3` redefines completely how the data is output and allows for nested type description;

## Features

- **Automatic derive macro** for `structs` and `enums`. `union` types are not supported.
- **Built-in implementations** for primitives, standard library types, and popular third-party crates.
- **Field-level attributes** for customization (`skip`, `as`, `rename`.)
- **Compact notation** for common patterns (e.g., `Option<T>``T?`.)
- **Optional feature flags** for third-party integrations.

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
describer = "0.3"
```

For third-party type support, enable the relevant features:

```toml
[dependencies]
describer = { version = "0.1.0", features = ["chrono", "uuid", "regex"] }
```

### Available Features

- `chrono` - Support for `DateTime`, `NaiveDate`, `NaiveDateTime`, `NaiveTime`.
- `uuid` - Support for `Uuid`.
- `regex` - Support for `Regex`.
- `http` - Support for HTTP types (`Request`, `Response`, `HeaderMap`, etc.).
- `tokio` - Support for Tokio's `Mutex` and `RwLock`.
- `indexmap` - Support for `IndexMap` and `IndexSet`.
- `dashmap` - Support for `DashMap` and `DashSet`.

## Basic Usage

```rust
use describer::{Describer, Describe};
use std::collections::HashMap;

// Primitives
assert_eq!(i32::describe(), "i32");
assert_eq!(String::describe(), "String");

// Standard library types
assert_eq!(Vec::<u8>::describe(), "[u8]");
assert_eq!(Option::<i32>::describe(), "i32?");
assert_eq!(HashMap::<String, bool>::describe(), "{String: bool}");

// Custom types with derive macro
#[derive(Describe)]
struct User {
    id: u64,
    name: String,
    email: String,
}

assert_eq!(User::describe(), "User { id: u64, name: String, email: String }");
```

## Type Notation

The crate uses a compact notation system for common patterns:

| Type                 | Notation  | Example |
|----------------------|-----------|---------|
| `Optional`           | `T?`      | `i32?`           |
| `Result`             | `!{T, E}` | `!{String, i32}` |
| `Vec`/`Slice`        | `[T]`     | `[u8]`           |
| `HashMap`/`BTreeMap` | `{K: V}`  | `{String: i32}` |
| `HashSet`/`BTreeSet` | `#{T}`    | `#{String}`     |
| `BinaryHeap`         | `^[T]`    | `^[i32]`        |
| `Box`                | `*T`      | `*u8`           |
| `Arc`                | `arc T`   | `arc String` |
| `Rc`                 | `rc T`    | `rc i32`     |
| `Cell`/`RefCell`     | `&T`      | `&u32`       |
| `Cow`                | `~T`      | `~String`    |
| `Range` types        | `[T[`, `[T]`, etc. | `[i32[` |

## Derive Macro

### Structs

The derive macro works with named, unnamed (tuple), and unit structs:

```rust
use describer::{Describer, Describe};

// Named struct
#[derive(Describe)]
struct Point {
    x: f64,
    y: f64,
}
assert_eq!(Point::describe(), "Point { x: f64, y: f64 }");


// Tuple struct
#[derive(Describe)]
struct Color(u8, u8, u8);
assert_eq!(Color::describe(), "Color(u8, u8, u8)");

// Unit struct
#[derive(Describe)]
struct Marker;
assert_eq!(Marker::describe(), "Marker");
```

### Enums

Enums are represented with all their variants separated by ` | `:

```rust
use describer::{Describer, Describe};

#[derive(Describe)]
enum Status {
    Active,
    Pending(String),
    Error { code: i32, message: String },
}
assert_eq!(Status::describe(),  "Status #{ Active | Pending(String) | Error { code: i32, message: String } }");
```

## Field Attributes

Customize field descriptions using the `#[describe(...)]` attribute:

### `skip` - Omit a field

```rust
use describer::{Describer, Describe};

#[derive(Describe)]
struct User {
    id: u64,
    #[describe(skip)]
    password: String,
    email: String,
}
assert_eq!(User::describe(), "User { id: u64, email: String }");
```

### `with = "..."` - Use a custom type name

Replaces the actual type with a custom string:

```rust
use describer::{Describer, Describe};

#[derive(Describe)]
struct Config {
    #[describe(with = "Milliseconds")]
    timeout: u64,
    #[describe(with = "URL")]
    server: String,
}
assert_eq!(Config::describe(), "Config { timeout: Milliseconds, server: URL }");
```

### `rename = "..."` - Rename the field

Changes the field name in the output (note: the actual attribute is `rename`, though `as` can be used for type names):

```rust
use describer::{Describer, Describe};

#[derive(Describe)]
struct Person {
    #[describe(rename = "identifier")]
    id: u64,
    name: String,
}
assert_eq!(Person::describe(), "Person { identifier: u64, name: String }");
```

### Combining Attributes

```rust
use describer::{Describer, Describe};

#[derive(Describe)]
struct ApiResponse {
    #[describe(skip)]
    internal_id: String,
    #[describe(rename = "timestamp", with = "UnixTimestamp")]
    created_at: i64,
    data: Vec<u8>,
}
assert_eq!(ApiResponse::describe(), "ApiResponse { timestamp: UnixTimestamp, data: [u8] }");
```

## Built-in Type Support

### Primitives

All Rust primitives are supported: `i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `f32`, `f64`, `bool`, `char`, `String`, `str`

### Standard Library Collections

- **Sequences**: `Vec<T>`, `VecDeque<T>`, `LinkedList<T>`, `BinaryHeap<T>`, `[T]`
- **Maps**: `HashMap<K, V>`, `BTreeMap<K, V>`
- **Sets**: `HashSet<T>`, `BTreeSet<T>`

### Smart Pointers & Concurrency

- **Owned**: `Box<T>`, `Arc<T>`, `Rc<T>`
- **Interior Mutability**: `Cell<T>`, `RefCell<T>`, `Mutex<T>`, `RwLock<T>`
- **Copy-on-Write**: `Cow<T>`

### Ranges

All range types: `Range<T>`, `RangeFrom<T>`, `RangeTo<T>`, `RangeInclusive<T>`, `RangeToInclusive<T>`, `RangeFull`

### Tuples

Tuples up to 12 elements are supported:

```rust
use describer::{Describer, Describe};

assert_eq!(<(i32, String, bool)>::describe(), "(i32, String, bool)");
```

### Third-Party Types (with features)

When enabled via feature flags:

- **chrono**: `DateTime<Tz>`, `NaiveDate`, `NaiveDateTime`, `NaiveTime`
- **uuid**: `Uuid`
- **regex**: `Regex`
- **http**: `Request<T>`, `Response<T>`, `HeaderMap`, `Method`, `Uri`, `StatusCode`, `Version`, `Extensions`
- **tokio**: `tokio::sync::Mutex<T>`, `tokio::sync::RwLock<T>`
- **indexmap**: `IndexMap<K, V>`, `IndexSet<T>`
- **dashmap**: `DashMap<K, V>`, `DashSet<T>`

## Use Cases

### API Documentation

Generate human-readable type signatures for API endpoints:

```rust
use describer::{Describer, Describe};

#[derive(Describe)]
struct CreateUserRequest {
    username: String,
    email: String,
    #[describe(skip)]
    password: String,
}

fn document_endpoint() {
    println!("POST /users - Body: {}", CreateUserRequest::describe());
    // Output: "POST /users - Body: CreateUserRequest { username: String, email: String }"
}
```

### Schema Generation

```rust
use describer::{Describer, Describe};
use std::collections::HashMap;

#[derive(Describe)]
struct DatabaseRecord {
    #[describe(with = "UUID")]
    id: String,
    #[describe(with = "Timestamp")]
    created_at: i64,
    data: HashMap<String, String>,
}

// DatabaseRecord::describe(), "DatabaseRecord { id: UUID, created_at: Timestamp, data: {String: String} }"
```

### Type Introspection

```rust
use describer::{Describer, Describe};

#[derive(Describe)]
enum Message {
    Text(String),
    Binary(Vec<u8>),
    Close { code: u16, reason: String },
}

fn log_message_types() {
    println!("Supported message types: {}", Message::describe());
}
```

## Limitations

- **No generics support**: The current version does not support generic types in custom structs/enums
- **No lifetime support**: Lifetimes are not included in descriptions
- **Unions not supported**: Only structs and enums can use the derive macro

## Examples

### Complex Nested Types

```rust
use describer::{Describer, Describe};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;

type ComplexType = Result<Vec<Option<HashMap<String, Arc<Mutex<u64>>>>>, String>;

assert_eq!(
    ComplexType::describe(),
    "!{[{String: arc u64}?], String}"
);
```

### Real-World Example

```rust
use describer::{Describer, Describe};
use std::collections::HashMap;

#[derive(Describe)]
struct ApiConfig {
    #[describe(with = "URL")]
    base_url: String,
    #[describe(with = "Milliseconds")]
    timeout: u64,
    #[describe(skip)]
    api_key: String,
    retry_count: u32,
    headers: HashMap<String, String>,
}

#[derive(Describe)]
enum ApiResponse {
    Success {
        data: Vec<u8>,
        #[describe(with = "UnixTimestamp")]
        timestamp: i64,
    },
    Error {
        code: u16,
        message: String,
    },
}

println!("Config: {}", ApiConfig::describe());
// Config: "ApiConfig { base_url: URL, timeout: Milliseconds, retry_count: u32, headers: {String: String} }"
assert_eq!(ApiConfig::describe(), "ApiConfig { base_url: URL, timeout: Milliseconds, retry_count: u32, headers: {String: String} }");

println!("Response: {}", ApiResponse::describe());
// Response: "ApiResponse { Success { data: [u8], timestamp: UnixTimestamp } | Error { code: u16, message: String } }"
assert_eq!(ApiResponse::describe(), "ApiResponse #{ Success { data: [u8], timestamp: UnixTimestamp } | Error { code: u16, message: String } }");
```

## Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

## TODO:
- [] Support generic types
- [] Allow remote implementation, like `#[serde(remote = "...")]`