//! Typed read/write access to [`toml_edit`] documents via `#[derive(TomlEdit)]`,
//! preserving comments and formatting.
//!
//! `toml_edit` keeps a document's exact layout but exposes it through
//! stringly-typed `doc["key"]` indexing. Deriving [`TomlEdit`] on your structs
//! and enums generates typed accessors whose edits flow back into the original
//! document, leaving comments and whitespace intact.
//!
//! # Example
//!
//! ```
//! use toml_edit_derive::TomlEdit;
//!
//! #[derive(TomlEdit)]
//! # #[allow(dead_code)]
//! struct Config {
//!     name: String,
//!     retries: i64,
//! }
//!
//! let mut doc =
//!     ConfigTomlEdit::parse("# my app\nname = \"app\"\nretries = 3\n").unwrap();
//!
//! // typed reads
//! assert_eq!(doc.name(), Some("app".to_owned()));
//! assert_eq!(doc.retries(), Some(3));
//!
//! // typed write — the comment survives
//! doc.retries_mut().set(5);
//! let out = doc.to_toml_string();
//! assert!(out.contains("# my app"));
//! assert!(out.contains("retries = 5"));
//! ```
//!
//! # Generated items
//!
//! For `#[derive(TomlEdit)] struct Foo`:
//!
//! - `FooTomlEdit` — owns a [`DocumentMut`]; `parse` / `to_toml_string` plus
//!   `field()` / `field_mut()` accessors.
//! - `FooTomlEditView<'a>` — borrowed read-only view (for nested values).
//! - `FooTomlEditMut<'a>` — borrowed mutable view.
//!
//! See the [crate README](https://docs.rs/crate/toml-edit-derive) for the full
//! list of supported field types and `serde` attributes.

use std::fmt;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::path::PathBuf;

pub use toml_edit::{Array, ArrayOfTables, DocumentMut, Item, Table, TableLike, TomlError, Value};
pub use toml_edit_derive_macro::TomlEdit;

/// Implemented by user-defined types that serialize to a TOML value (e.g. unit enums).
pub trait TomlEditValue: Sized {
    fn from_value(v: &Value) -> Option<Self>;
    fn into_value(self) -> Value;
}

impl TomlEditValue for String {
    fn from_value(v: &Value) -> Option<Self> {
        v.as_str().map(|s| s.to_owned())
    }
    fn into_value(self) -> Value {
        Value::from(self)
    }
}

impl TomlEditValue for bool {
    fn from_value(v: &Value) -> Option<Self> {
        v.as_bool()
    }
    fn into_value(self) -> Value {
        Value::from(self)
    }
}

impl TomlEditValue for f64 {
    fn from_value(v: &Value) -> Option<Self> {
        v.as_float()
    }
    fn into_value(self) -> Value {
        Value::from(self)
    }
}

/// Stored as a TOML float (`f64`); reading back may lose precision for values that don't round-trip exactly through `f64`.
impl TomlEditValue for f32 {
    fn from_value(v: &Value) -> Option<Self> {
        v.as_float().map(|n| n as f32)
    }
    fn into_value(self) -> Value {
        Value::from(self as f64)
    }
}

// TOML integers are i64; both directions use checked conversion to avoid silent truncation.
macro_rules! impl_toml_edit_value_int {
    ($($t:ty),*) => {
        $(impl TomlEditValue for $t {
            fn from_value(v: &Value) -> Option<Self> {
                v.as_integer().and_then(|n| <$t>::try_from(n).ok())
            }
            fn into_value(self) -> Value {
                Value::from(i64::try_from(self).expect("value out of TOML integer range (i64)"))
            }
        })*
    };
}
impl_toml_edit_value_int!(
    i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize, isize
);

/// Stored as a TOML string. Lossy for non-UTF-8 paths (TOML is UTF-8).
impl TomlEditValue for PathBuf {
    fn from_value(v: &Value) -> Option<Self> {
        v.as_str().map(PathBuf::from)
    }
    fn into_value(self) -> Value {
        Value::from(self.to_string_lossy().into_owned())
    }
}

/// Stored as a TOML string; an unparseable string reads back as `None`.
impl TomlEditValue for SocketAddr {
    fn from_value(v: &Value) -> Option<Self> {
        v.as_str().and_then(|s| s.parse().ok())
    }
    fn into_value(self) -> Value {
        Value::from(self.to_string())
    }
}

/// Transfer inline decor (spacing, trailing comments) from an existing slot to a new item.
/// Only transfers when both old and new are `Item::Value` — value-level decor (e.g. `# comment`)
/// cannot meaningfully survive a type change from scalar to table, so it is intentionally dropped.
fn transfer_value_decor(old: &Item, new: &mut Item) {
    if let (Item::Value(old_val), Item::Value(new_val)) = (old, new) {
        *new_val.decor_mut() = old_val.decor().clone();
    }
}

/// Entry handle for a single TOML field, mirroring [`Option`] semantics.
///
/// Absent key ↔ `None`; present key ↔ `Some`. Returned by generated `field_mut()` accessors.
pub struct FieldEntry<'a, T: TomlEditable> {
    table: &'a mut dyn TableLike,
    key: &'static str,
    _phantom: PhantomData<fn() -> T>,
}

impl<'a, T: TomlEditable> FieldEntry<'a, T> {
    pub fn new(table: &'a mut dyn TableLike, key: &'static str) -> Self {
        Self {
            table,
            key,
            _phantom: PhantomData,
        }
    }

    pub fn is_some(&self) -> bool {
        self.table.contains_key(self.key)
    }

    pub fn is_none(&self) -> bool {
        !self.is_some()
    }

    /// Read the current value (borrows from the document).
    pub fn get(&self) -> Option<T::View<'_>> {
        self.table.get(self.key).and_then(T::from_item)
    }

    /// Mutable handle to the existing value; `None` when the key is absent.
    pub fn get_mut(&mut self) -> Option<T::Mut<'_>> {
        self.table.get_mut(self.key).and_then(T::from_item_mut)
    }

    /// Always write `v`, replacing any existing value. Preserves key position and inline decor (comments, spacing).
    pub fn set(&mut self, v: T) {
        let mut item = T::into_item(v);
        match self.table.get_mut(self.key) {
            Some(slot) => {
                transfer_value_decor(slot, &mut item);
                *slot = item;
            }
            None => {
                self.table.insert(self.key, item);
            }
        }
    }

    fn insert_if_absent(mut self, item: Item) -> T::Mut<'a> {
        if self.get_mut().is_none() {
            self.table.insert(self.key, item);
            debug_assert!(
                self.table
                    .get_mut(self.key)
                    .and_then(T::from_item_mut)
                    .is_some(),
                "insert_if_absent: T::empty_item() or T::into_item() produced an item \
                 incompatible with T::from_item_mut — check that empty_item() is consistent"
            );
        }
        self.get_mut_present()
    }

    /// Return a mutable handle, inserting `default` first if the key is absent or the wrong type.
    pub fn get_or_insert(self, default: T) -> T::Mut<'a> {
        self.insert_if_absent(T::into_item(default))
    }

    /// Return a mutable handle, inserting the value from `f` first if the key is absent or the wrong type.
    pub fn get_or_insert_with(self, f: impl FnOnce() -> T) -> T::Mut<'a> {
        self.insert_if_absent(T::into_item(f()))
    }

    /// Return a mutable handle, inserting an empty value first if the key is absent or the wrong type.
    /// For struct types inserts an empty table; for `Vec<T>` inserts an empty array.
    pub fn get_or_insert_empty(self) -> T::Mut<'a> {
        self.insert_if_absent(T::empty_item())
    }

    /// Return a mutable handle, inserting `T::default()` first if the key is absent or the wrong type.
    pub fn get_or_insert_default(self) -> T::Mut<'a>
    where
        T: Default,
    {
        self.insert_if_absent(T::into_item(T::default()))
    }

    fn get_mut_present(self) -> T::Mut<'a> {
        self.table
            .get_mut(self.key)
            .and_then(T::from_item_mut)
            .expect("entry missing after insert")
    }

    /// Return the mutable handle, panicking if the key is absent.
    #[track_caller]
    pub fn unwrap(self) -> T::Mut<'a> {
        self.table
            .get_mut(self.key)
            .and_then(T::from_item_mut)
            .unwrap_or_else(|| {
                panic!(
                    "called `FieldEntry::unwrap()` on a missing or wrong-type key `{}`",
                    self.key
                )
            })
    }

    /// Return the mutable handle, panicking with `msg` if the key is absent.
    #[track_caller]
    pub fn expect(self, msg: &str) -> T::Mut<'a> {
        self.table
            .get_mut(self.key)
            .and_then(T::from_item_mut)
            .unwrap_or_else(|| panic!("{}", msg))
    }

    /// Remove the key and return whether it was present.
    pub fn remove(&mut self) -> bool {
        self.table.remove(self.key).is_some()
    }

    /// Replace the value, returning a mutable handle to it. Preserves key position and inline decor.
    pub fn replace(self, v: T) -> T::Mut<'a> {
        let mut item = T::into_item(v);
        match self.table.get_mut(self.key) {
            Some(slot) => {
                transfer_value_decor(slot, &mut item);
                *slot = item;
            }
            None => {
                self.table.insert(self.key, item);
            }
        }
        self.get_mut_present()
    }

    /// Mutate the entry if present. Closure receives mutable handle.
    pub fn and_mutate<F>(mut self, f: F) -> bool
    where
        F: FnOnce(&mut T::Mut<'_>),
    {
        if let Some(mut m) = self.get_mut() {
            f(&mut m);
            true
        } else {
            false
        }
    }
}

impl<T: TomlEditable> fmt::Debug for FieldEntry<'_, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FieldEntry").finish()
    }
}

enum ValueOrItem<'a> {
    Value(&'a mut Value),
    Item(&'a mut Item),
}

/// Mutable proxy over the [`Item`] or [`Value`] slot holding a [`TomlEditValue`] (e.g. a unit enum).
///
/// Lets value-typed struct fields expose a working `*_mut()` accessor instead of
/// one that always yields `None`.
pub struct TomlEditValueMut<'a, T: TomlEditValue> {
    inner: ValueOrItem<'a>,
    _marker: PhantomData<fn() -> T>,
}

impl<'a, T: TomlEditValue> TomlEditValueMut<'a, T> {
    pub fn new(item: &'a mut Item) -> Self {
        Self {
            inner: ValueOrItem::Item(item),
            _marker: PhantomData,
        }
    }

    pub(crate) fn from_value(v: &'a mut Value) -> Self {
        Self {
            inner: ValueOrItem::Value(v),
            _marker: PhantomData,
        }
    }

    pub fn get(&self) -> Option<T> {
        match &self.inner {
            ValueOrItem::Value(v) => T::from_value(v),
            ValueOrItem::Item(i) => i.as_value().and_then(|v| T::from_value(v)),
        }
    }

    pub fn set(&mut self, v: T) {
        let mut new_val = T::into_value(v);
        match &mut self.inner {
            ValueOrItem::Value(slot) => {
                *new_val.decor_mut() = slot.decor().clone();
                **slot = new_val;
            }
            ValueOrItem::Item(slot) => {
                if let Item::Value(ref old_val) = **slot {
                    *new_val.decor_mut() = old_val.decor().clone();
                }
                **slot = Item::Value(new_val);
            }
        }
    }
}

impl<T: TomlEditValue> fmt::Debug for TomlEditValueMut<'_, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TomlEditValueMut").finish()
    }
}

impl<T: TomlEditValue> TomlEditable for T {
    type View<'a> = T;
    type Mut<'a> = TomlEditValueMut<'a, T>;

    const IS_VALUE_TYPE: bool = true;

    fn from_value(v: &Value) -> Option<T> {
        <T as TomlEditValue>::from_value(v)
    }
    fn from_item(item: &Item) -> Option<T> {
        item.as_value()
            .and_then(|v| <T as TomlEditValue>::from_value(v))
    }
    fn from_item_mut(item: &mut Item) -> Option<TomlEditValueMut<'_, T>> {
        item.is_value().then(|| TomlEditValueMut::new(item))
    }
    fn from_value_mut(v: &mut Value) -> Option<TomlEditValueMut<'_, T>> {
        Some(TomlEditValueMut::from_value(v))
    }
    fn into_item(self) -> Item {
        Item::Value(T::into_value(self))
    }
}

/// Implemented by user-defined types that map to TOML tables (structs and struct enums).
#[diagnostic::on_unimplemented(
    message = "`{Self}` must `#[derive(TomlEdit)]` to be used as a TOML field",
    label = "add `#[derive(TomlEdit)]` to this type"
)]
pub trait TomlEditable: Sized {
    type View<'a>;
    type Mut<'a>;

    /// `true` for types that serialize as a TOML *value* (scalars, unit enums, PathBuf…).
    /// `false` for types that serialize as a TOML *table* (structs with `#[derive(TomlEdit)]`).
    const IS_VALUE_TYPE: bool = false;

    fn from_item(item: &Item) -> Option<Self::View<'_>> {
        item.as_table_like().and_then(Self::from_table_like)
    }
    /// Build a borrowed view from any table-like ([`Table`] or inline table).
    fn from_table_like(table: &dyn TableLike) -> Option<Self::View<'_>> {
        let _ = table;
        None
    }
    fn from_value(_v: &Value) -> Option<Self::View<'_>> {
        None
    }
    fn from_item_mut(item: &mut Item) -> Option<Self::Mut<'_>> {
        item.as_table_like_mut().and_then(Self::from_table_like_mut)
    }
    fn from_table_like_mut(table: &mut dyn TableLike) -> Option<Self::Mut<'_>> {
        let _ = table;
        None
    }
    fn from_value_mut(_v: &mut Value) -> Option<Self::Mut<'_>> {
        None
    }
    fn into_item(self) -> Item;
    /// The item inserted by `get_or_insert_empty` / `TomlEditMapMut::insert_empty`.
    ///
    /// Default: `Item::Table(Table::new())` (correct for struct types and maps).
    /// `Vec<T>` overrides this to return an empty array of the appropriate kind.
    ///
    /// **Invariant:** the returned `Item` must be accepted by `from_item_mut`; violating this
    /// causes `insert_empty` to panic at "entry missing after insert".
    fn empty_item() -> Item {
        Item::Table(Table::new())
    }
}

macro_rules! impl_toml_editable_map {
    ($map:ident) => {
        impl<T: TomlEditable + 'static> TomlEditable for ::std::collections::$map<String, T> {
            type View<'a> = ::std::collections::$map<String, T::View<'a>>;
            type Mut<'a> = TomlEditMapMut<'a, T>;

            fn from_item(item: &Item) -> Option<Self::View<'_>> {
                item.as_table_like().and_then(Self::from_table_like)
            }
            fn from_table_like(table: &dyn TableLike) -> Option<Self::View<'_>> {
                Some(
                    table
                        .iter()
                        .filter_map(|(k, i)| Some((k.to_owned(), T::from_item(i)?)))
                        .collect(),
                )
            }
            fn from_item_mut(item: &mut Item) -> Option<TomlEditMapMut<'_, T>> {
                item.as_table_like_mut().map(TomlEditMapMut::new)
            }
            fn into_item(self) -> Item {
                let mut __tbl = Table::new();
                for (k, v) in self {
                    __tbl.insert(&k, T::into_item(v));
                }
                Item::Table(__tbl)
            }
        }
    };
}
impl_toml_editable_map!(HashMap);
impl_toml_editable_map!(BTreeMap);

impl<T: TomlEditable + 'static> TomlEditable for Vec<T> {
    type View<'a> = Vec<T::View<'a>>;
    type Mut<'a> = TomlEditArrayMut<'a, T>;

    fn from_item(item: &Item) -> Option<Vec<T::View<'_>>> {
        if let Some(arr) = item.as_array() {
            Some(arr.iter().filter_map(T::from_value).collect())
        } else {
            item.as_array_of_tables()
                .map(|aot| aot.iter().filter_map(|t| T::from_table_like(t)).collect())
        }
    }

    fn from_item_mut(item: &mut Item) -> Option<TomlEditArrayMut<'_, T>> {
        match item {
            Item::Value(Value::Array(arr)) => Some(TomlEditArrayMut::new_values(arr)),
            Item::ArrayOfTables(aot) => Some(TomlEditArrayMut::new(aot)),
            _ => None,
        }
    }

    fn empty_item() -> Item {
        if T::IS_VALUE_TYPE {
            Item::Value(Value::Array(Array::new()))
        } else {
            Item::ArrayOfTables(ArrayOfTables::new())
        }
    }

    fn into_item(self) -> Item {
        let mut arr = Array::new();
        let mut aot = ArrayOfTables::new();
        let mut saw_values = false;
        let mut saw_tables = false;
        for v in self {
            match T::into_item(v) {
                Item::Value(val) => {
                    saw_values = true;
                    arr.push(val);
                }
                Item::Table(tbl) => {
                    saw_tables = true;
                    aot.push(tbl);
                }
                // Item::ArrayOfTables / Item::None: not emitted by any derived impl
                _ => {}
            }
        }
        assert!(
            !(saw_values && saw_tables),
            "Vec<T>::into_item: T produced both Value and Table items; \
             every element must serialize to the same shape"
        );
        assert!(
            !(T::IS_VALUE_TYPE && saw_tables),
            "Vec<T>::into_item: T::IS_VALUE_TYPE is true but into_item produced Item::Table; \
             IS_VALUE_TYPE must match the actual serialization shape"
        );
        if T::IS_VALUE_TYPE || saw_values {
            Item::Value(Value::Array(arr))
        } else {
            Item::ArrayOfTables(aot)
        }
    }
}

enum ArrayMutStorage<'a> {
    Values(&'a mut Array),
    Tables(&'a mut ArrayOfTables),
}

enum EitherIter<L: Iterator, R: Iterator<Item = L::Item>> {
    Left(L),
    Right(R),
}

impl<L: Iterator, R: Iterator<Item = L::Item>> Iterator for EitherIter<L, R> {
    type Item = L::Item;
    fn next(&mut self) -> Option<Self::Item> {
        match self {
            Self::Left(l) => l.next(),
            Self::Right(r) => r.next(),
        }
    }
}

impl<L, R> std::iter::FusedIterator for EitherIter<L, R>
where
    L: std::iter::FusedIterator,
    R: std::iter::FusedIterator<Item = L::Item>,
{
}

/// Generic mutable proxy over an array of `T` entries.
///
/// Backed by either a TOML value array ([`Array`]) or an array of tables
/// ([`ArrayOfTables`]). All methods work for both storage kinds except
/// [`push_empty`](Self::push_empty), which is only valid for table-backed arrays.
pub struct TomlEditArrayMut<'a, T: TomlEditable> {
    storage: ArrayMutStorage<'a>,
    _marker: PhantomData<fn() -> T>,
}

impl<'a, T: TomlEditable> TomlEditArrayMut<'a, T> {
    pub fn new(arr: &'a mut ArrayOfTables) -> Self {
        Self {
            storage: ArrayMutStorage::Tables(arr),
            _marker: PhantomData,
        }
    }

    fn new_values(arr: &'a mut Array) -> Self {
        Self {
            storage: ArrayMutStorage::Values(arr),
            _marker: PhantomData,
        }
    }

    pub fn len(&self) -> usize {
        match &self.storage {
            ArrayMutStorage::Values(a) => a.len(),
            ArrayMutStorage::Tables(a) => a.len(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn get(&self, index: usize) -> Option<T::View<'_>> {
        match &self.storage {
            ArrayMutStorage::Values(a) => a.get(index).and_then(|v| T::from_value(v)),
            ArrayMutStorage::Tables(a) => a.get(index).and_then(|t| T::from_table_like(t)),
        }
    }

    pub fn get_mut(&mut self, index: usize) -> Option<T::Mut<'_>> {
        match &mut self.storage {
            ArrayMutStorage::Values(a) => a.get_mut(index).and_then(|v| T::from_value_mut(v)),
            ArrayMutStorage::Tables(a) => a.get_mut(index).and_then(|t| T::from_table_like_mut(t)),
        }
    }

    pub fn iter(&self) -> impl Iterator<Item = T::View<'_>> + '_ {
        match &self.storage {
            ArrayMutStorage::Values(a) => {
                EitherIter::Left(a.iter().filter_map(|v| T::from_value(v)))
            }
            ArrayMutStorage::Tables(a) => {
                EitherIter::Right(a.iter().filter_map(|t| T::from_table_like(t)))
            }
        }
    }

    /// Entries with incompatible shape are silently skipped (same semantics as [`iter`](Self::iter)).
    pub fn iter_mut(&mut self) -> impl Iterator<Item = T::Mut<'_>> + '_ {
        match &mut self.storage {
            ArrayMutStorage::Values(a) => {
                EitherIter::Left(a.iter_mut().filter_map(|v| T::from_value_mut(v)))
            }
            ArrayMutStorage::Tables(a) => {
                EitherIter::Right(a.iter_mut().filter_map(|t| T::from_table_like_mut(t)))
            }
        }
    }

    /// Append an empty table entry and return a mutable handle to it.
    ///
    /// # Panics
    ///
    /// Panics if the array is value-backed (`Vec<scalar>` field) — use
    /// [`FieldEntry::set`] to replace the whole `Vec` instead. Also panics if
    /// `T` does not implement `from_table_like_mut` (i.e. is not a
    /// `#[derive(TomlEdit)]` struct).
    #[must_use]
    pub fn push_empty(&mut self) -> T::Mut<'_> {
        match &mut self.storage {
            ArrayMutStorage::Values(_) => panic!(
                "`push_empty` called on a value-backed array (`Vec<scalar>`). \
                 Use `FieldEntry::set` to replace the whole `Vec` instead."
            ),
            ArrayMutStorage::Tables(a) => {
                a.push(Table::new());
                let last = a.len() - 1;
                T::from_table_like_mut(a.get_mut(last).unwrap()).expect(
                    "`push_empty` requires T to be a struct type with `#[derive(TomlEdit)]`",
                )
            }
        }
    }

    pub fn remove(&mut self, index: usize) {
        match &mut self.storage {
            ArrayMutStorage::Values(a) => {
                a.remove(index);
            }
            ArrayMutStorage::Tables(a) => {
                a.remove(index);
            }
        }
    }

    /// Convenience method: get mutable handle to element at index. Equivalent to `self.get_mut(index)`.
    pub fn at(&mut self, index: usize) -> Option<T::Mut<'_>> {
        self.get_mut(index)
    }

    /// Clear all elements from the array.
    pub fn clear(&mut self) {
        match &mut self.storage {
            ArrayMutStorage::Values(a) => a.clear(),
            ArrayMutStorage::Tables(a) => a.clear(),
        }
    }
}

impl<T: TomlEditable> fmt::Debug for TomlEditArrayMut<'_, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TomlEditArrayMut").finish()
    }
}

/// Generic mutable proxy over a TOML table keyed by string mapping to `T` entries
/// (the backing type for `HashMap<String, T>` / `BTreeMap<String, T>` fields).
pub struct TomlEditMapMut<'a, T: TomlEditable> {
    table: &'a mut dyn TableLike,
    _marker: PhantomData<fn() -> T>,
}

impl<'a, T: TomlEditable> TomlEditMapMut<'a, T> {
    pub fn new(table: &'a mut dyn TableLike) -> Self {
        Self {
            table,
            _marker: PhantomData,
        }
    }
    pub fn len(&self) -> usize {
        self.table.len()
    }
    pub fn is_empty(&self) -> bool {
        self.table.is_empty()
    }
    pub fn contains_key(&self, key: &str) -> bool {
        self.table.contains_key(key)
    }
    pub fn get(&self, key: &str) -> Option<T::View<'_>> {
        self.table.get(key).and_then(T::from_item)
    }
    pub fn get_mut(&mut self, key: &str) -> Option<T::Mut<'_>> {
        self.table.get_mut(key).and_then(T::from_item_mut)
    }
    /// All table keys, including any whose value fails to convert to `T`.
    /// (Unlike [`iter`](Self::iter), which yields only convertible entries.)
    pub fn keys(&self) -> impl Iterator<Item = &str> + '_ {
        self.table.iter().map(|(k, _)| k)
    }
    /// Entries whose value converts to `T`; entries of other shapes are skipped.
    pub fn iter(&self) -> impl Iterator<Item = (&str, T::View<'_>)> + '_ {
        self.table
            .iter()
            .filter_map(|(k, i)| Some((k, T::from_item(i)?)))
    }
    /// Entries whose value converts to `T`. Entries with an incompatible shape (e.g. a table
    /// where a scalar is expected) are silently skipped, consistent with [`iter`](Self::iter).
    pub fn iter_mut(&mut self) -> impl Iterator<Item = (String, T::Mut<'_>)> + '_ {
        self.table
            .iter_mut()
            .filter_map(|(k, i)| Some((k.get().to_owned(), T::from_item_mut(i)?)))
    }
    /// Insert an empty value at `key` and return a mutable handle to it.
    /// Uses `T::empty_item()`: struct types insert an empty table; `Vec<T>` inserts an empty array.
    ///
    /// # Panics
    ///
    /// Panics if `T::from_item_mut` returns `None` for the inserted item (type mismatch).
    #[must_use]
    pub fn insert_empty(&mut self, key: &str) -> T::Mut<'_> {
        self.table.insert(key, T::empty_item());
        T::from_item_mut(self.table.get_mut(key).unwrap()).expect(
            "`insert_empty`: T::empty_item() produced an item incompatible with T::from_item_mut; \
                     ensure empty_item() and from_item_mut() are consistent",
        )
    }
    pub fn remove(&mut self, key: &str) {
        self.table.remove(key);
    }
}

impl<T: TomlEditable> fmt::Debug for TomlEditMapMut<'_, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TomlEditMapMut").finish()
    }
}
