serde_field_result 0.1.0

Field-level Serde recovery for schema-drift-tolerant API clients
Documentation
# serde_field_result

[![Docs.rs](https://docs.rs/serde_field_result/badge.svg)](https://docs.rs/serde_field_result)
[![CI](https://github.com/gramistella/serde-field-result/actions/workflows/ci.yml/badge.svg)](https://github.com/gramistella/serde-field-result/actions/workflows/ci.yml)

Field-level Serde recovery for schema-drift-tolerant API clients.

```toml
serde_field_result = "0.1"
```

The core type is `Field<T>`:

```rust
use serde::Deserialize;
use serde_field_result::Field;

#[derive(Deserialize)]
struct Row {
    #[serde(default)] // required if absent fields should become Field::Missing
    price: Field<f64>,
}
```

A field can be:

```rust
Field::Missing
Field::Valid(value)
Field::Invalid(error)
```

This lets one bad field fail softly without destroying an otherwise useful
response.

You can inspect invalid fields without pattern matching every variant:

```rust
let mut warnings = Vec::new();

if let Some(error) = row.price.error() {
    warnings.push(format!("bad price: {error}"));
}
```

`Field<T>` is intentionally a three-state type, not a JSON patch type or a
generic `T: Deserialize` buffering wrapper. For ordinary `Field<T>` values, an
absent field, `null`, and Serde unit all decode as `Field::Missing`. Use
`Field<Option<T>>` when explicit `null` or unit should be a valid `None` while
an absent field remains `Field::Missing`.

For JSON-specific raw capture, enable the `json` feature. Use `JsonField<T>`
when the decoded value should own its data and invalid fields should retain an
owned `Box<serde_json::value::RawValue>`. Use `BorrowedJsonField<'de, T>` when
the original JSON input outlives the decoded value and you want invalid raw JSON
and valid nested values to borrow from that input. `BorrowedJsonField` has the
same borrowing limitations as `serde_json`: escaped strings may not deserialize
into `&'de str`, so use `String` or `Cow<'de, str>` when string values may need
unescaping.

`JsonField<Option<T>>` and `BorrowedJsonField<Option<T>>` do not distinguish
explicit JSON `null` from missing; JSON `null` is always `Missing`.

```toml
serde_field_result = { version = "0.1", features = ["json"] }
```

Default features enable `std`. For `no_std` environments with `alloc`, disable
default features and enable `alloc` explicitly:

```toml
serde_field_result = { version = "0.1", default-features = false, features = ["alloc"] }
```

The `json` feature also works without `std`; it enables `alloc` automatically.

```rust
use serde::Deserialize;
use serde_field_result::{BorrowedJsonField, JsonField};

#[derive(Deserialize)]
struct OwnedNested {
    value: String,
}

#[derive(Deserialize)]
struct BorrowedNested<'a> {
    #[serde(borrow)]
    value: &'a str,
}

#[derive(Deserialize)]
struct OwnedRow {
    #[serde(default)]
    nested: JsonField<OwnedNested>,
}

#[derive(Deserialize)]
struct BorrowedRow<'a> {
    #[serde(default, borrow)]
    nested: BorrowedJsonField<'a, BorrowedNested<'a>>,
}
```

For custom scalar-like types, prefer implementing `ScalarFieldDecode`. Implement
`FieldDecode` directly only when you are prepared to consume and drain every
unexpected Serde shape. In custom visitors, prefer `invalid_seq` and
`invalid_map` for unexpected arrays or objects; they drain the compound value
before returning `Field::Invalid`, preserving following sibling fields.

Default scalar type-mismatch errors are stored without formatting an owned error
message up front. Custom decoders can still use `FieldError::new` when an error
needs to include dynamic details.

The built-in primitive integer and float decoders accept JSON numbers, not
numeric strings. Implement a custom `ScalarFieldDecode` wrapper when an API
uses strings such as `"42"` or `"12.5"` for numbers. The built-in `f32` and
`f64` field decoders reject non-finite values. Integer-to-float conversions
follow Rust cast semantics and may lose precision.