borrowize 0.1.0

Derive borrowed view structs from owned Rust structs.
Documentation
# borrowize

`borrowize` provides `#[derive(View)]`, a small procedural macro for generating
borrowed view structs from owned structs.

The macro is useful when an API wants to expose a cheap borrowed projection of
an owned value without writing a second struct and conversion method by hand.

## Quick Start

```rust
use borrowize::View;

#[derive(Debug, PartialEq, Eq)]
struct Tag(&'static str);

#[derive(View)]
struct User {
    id: u64,
    name: String,
    tags: Vec<Tag>,
}

let user = User {
    id: 7,
    name: "Ada".to_owned(),
    tags: vec![Tag("admin"), Tag("editor")],
};

let view = user.view();

assert_eq!(*view.id, 7);
assert_eq!(view.name, "Ada");
assert_eq!(view.tags, [Tag("admin"), Tag("editor")]);
```

This generates a sibling view type similar to:

```rust
struct UserView<'borrowize> {
    id: &'borrowize u64,
    name: &'borrowize str,
    tags: &'borrowize [Tag],
}

impl User {
    fn view(&self) -> UserView<'_> {
        UserView {
            id: &self.id,
            name: self.name.as_str(),
            tags: self.tags.as_slice(),
        }
    }
}
```

The generated lifetime is always named `'borrowize` inside generated view type
definitions. Source structs may not define a lifetime with that name.

## Default Mapping

`borrowize` maps common owned field types to borrowed forms:

| Source field type | Generated view field type     | Generated expression           |
| ----------------- | ----------------------------- | ------------------------------ |
| `String`          | `&'borrowize str`             | `self.field.as_str()`          |
| `Vec<T>`          | `&'borrowize [T]`             | `self.field.as_slice()`        |
| `[T; N]`          | `&'borrowize [T]`             | `&self.field[..]`              |
| `Box<T>`          | `&'borrowize T`               | `self.field.as_ref()`          |
| `PathBuf`         | `&'borrowize std::path::Path` | `self.field.as_path()`         |
| `Option<T>`       | `Option<Borrowed<T>>`         | `self.field.as_ref().map(...)` |
| `&'a T`           | `&'a T`                       | `self.field`                   |
| other `T`         | `&'borrowize T`               | `&self.field`                  |

`Option<T>` is mapped recursively, so `Option<String>` becomes
`Option<&'borrowize str>` and `Option<u64>` becomes `Option<&'borrowize u64>`.

Type matching is syntactic. The macro recognises unqualified names and common
standard-library qualified names such as `std::string::String`,
`alloc::string::String`, `std::vec::Vec`, `alloc::vec::Vec`,
`std::option::Option`, `core::option::Option`, `std::boxed::Box`,
`alloc::boxed::Box`, and `std::path::PathBuf`. Type aliases are treated as
unknown types and are borrowed as `&T`.

## Struct Options

Struct-level options are written as `#[borrowize(...)]` on the source struct.
Names are explicit; there are no shorthand options.

```rust
use borrowize::View;

#[derive(View)]
#[borrowize(
    view_name = "UserParts",
    view_visibility = "pub",
    field_visibility = "pub",
    method_name = "as_parts",
    method_visibility = "pub"
)]
pub struct User {
    id: u64,
    name: String,
}
```

Supported struct options:

| Option                      | Meaning                                               |
| --------------------------- | ----------------------------------------------------- |
| `view_name = "Name"`        | Override the generated view type name.                |
| `view_visibility = "pub"`   | Override the generated view type visibility.          |
| `field_visibility = "pub"`  | Set the default visibility for generated view fields. |
| `method_name = "name"`      | Override the generated method name.                   |
| `method_visibility = "pub"` | Override the generated method visibility.             |
| `no_method`                 | Do not generate the inherent view method.             |

When a visibility option is omitted, visibility is inherited from the source
item or field. Explicit visibility values must be legal Rust visibility syntax,
such as `pub`, `pub(crate)`, or `pub(super)`.

`no_method` cannot be combined with `method_name` or `method_visibility`.

## Field Options

Field-level options are written as `#[borrowize(...)]` on a source field.

```rust
use borrowize::View;

#[derive(View)]
struct Encoded {
    #[borrowize(
        borrowed_type = "&'borrowize str",
        generation_expression = "::std::str::from_utf8(&self.bytes).expect(\"valid utf8\")"
    )]
    bytes: Vec<u8>,
}
```

Supported field options:

| Option                           | Meaning                                                      |
| -------------------------------- | ------------------------------------------------------------ |
| `borrowed_type = "Type"`         | Override the generated view field type.                      |
| `generation_expression = "expr"` | Override the generated field initializer in the view method. |
| `visibility = "pub"`             | Override this generated view field's visibility.             |

`borrowed_type` overrides may refer to the generated borrow lifetime as
`'borrowize`.

`generation_expression` is parsed as a Rust expression in the generated method
body. It can refer to `self` because the generated method borrows `&self`.

## Manual View Construction

Generated view fields inherit source field visibility by default. Use
`field_visibility` or field-level `visibility` when views need to be assembled
outside the source module.

```rust
use borrowize::View;

#[derive(View)]
#[borrowize(view_visibility = "pub", field_visibility = "pub", no_method)]
pub struct PublicSource {
    id: u64,
    name: String,
}

let id = 21;
let view = PublicSourceView {
    id: &id,
    name: "manual",
};
```

This is useful when you have borrowed pieces available before you have an owned
source value to call `view()` on.

## Generics

Source generics, const generics, lifetimes, and where clauses are preserved on
the generated view type and inherent method.

```rust
use borrowize::View;

#[derive(View)]
struct Generic<'a, T, const N: usize>
where
    T: 'a,
{
    name: String,
    items: Vec<T>,
    borrowed: &'a T,
    fixed: [u8; N],
}
```

## Current Limitations

`View` currently supports named-field structs only. Enums, unions, tuple
structs, and unit structs produce compile errors.

The generated inherent method can conflict with a user-defined method of the
same name. Use `method_name` to choose a different method name or `no_method`
when only the view type is needed.

Nested custom view conversion is not inferred. Unknown types are borrowed as
`&T`, even if they also derive `View`.

Type matching is syntactic, so aliases and re-exports of recognised container
types are not expanded.

The generated lifetime name `'borrowize` is reserved.

## Licence

`borrowize` is distributed under the terms of both the MIT licence and the
Apache License, Version 2.0. You may use it under either licence, at your
option.

See `LICENSE-MIT` and `LICENSE-APACHE` for the full licence texts.

## Contributions

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in `borrowize` is licensed as MIT OR Apache-2.0, without any
additional terms or conditions.