#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(nightly, feature(never_type))]
#![allow(dead_code)] // some code is tested for type checking only

#[cfg(not(feature = "std"))]
extern crate alloc;

#[cfg(not(feature = "std"))]
use alloc::{format, string::ToString};

use derive_more::with_trait::{
    Binary, Display, LowerExp, LowerHex, Octal, Pointer, UpperExp, UpperHex,
};

mod structs {
    use super::*;

    mod unit {
        use super::*;

        #[derive(Display)]
        struct Unit;

        #[derive(Display)]
        struct r#RawUnit;

        #[derive(Display)]
        struct Tuple();

        #[derive(Display)]
        struct Struct {}

        #[test]
        fn assert() {
            assert_eq!(Unit.to_string(), "Unit");
            assert_eq!(r#RawUnit.to_string(), "RawUnit");
            assert_eq!(Tuple().to_string(), "Tuple");
            assert_eq!(Struct {}.to_string(), "Struct");
        }

        mod str {
            use super::*;

            #[derive(Display)]
            #[display("unit")]
            pub struct Unit;

            #[derive(Display)]
            #[display("tuple")]
            pub struct Tuple();

            #[derive(Display)]
            #[display("struct")]
            pub struct Struct {}

            #[test]
            fn assert() {
                assert_eq!(Unit.to_string(), "unit");
                assert_eq!(Tuple().to_string(), "tuple");
                assert_eq!(Struct {}.to_string(), "struct");
            }
        }

        mod interpolated {
            use super::*;

            #[derive(Display)]
            #[display("unit: {}", 0)]
            pub struct Unit;

            #[derive(Display)]
            #[display("tuple: {}", 0)]
            pub struct Tuple();

            #[derive(Display)]
            #[display("struct: {}", 0)]
            pub struct Struct {}

            #[test]
            fn assert() {
                assert_eq!(Unit.to_string(), "unit: 0");
                assert_eq!(Tuple().to_string(), "tuple: 0");
                assert_eq!(Struct {}.to_string(), "struct: 0");
            }
        }

        mod transparency {
            use super::*;

            mod interpolated {
                use super::*;

                const I32: i32 = 11;
                const F64: f64 = 3.15;
                const POINTER: &f64 = &3.15;

                #[derive(Display)]
                #[display("{I32}")]
                struct Display;

                #[derive(Display)]
                #[display("{I32:?}")]
                struct Debug;

                #[derive(Display)]
                #[display("{:b}", I32)]
                struct Binary;

                #[derive(Display)]
                #[display("{0:o}", I32)]
                struct Octal;

                #[derive(Display)]
                #[display("{I32:x}")]
                struct LowerHex;

                #[derive(Display)]
                #[display("{:X}", I32)]
                struct UpperHex;

                #[derive(Display)]
                #[display("{F64:e}")]
                struct LowerExp;

                #[derive(Display)]
                #[display("{named:E}", named = F64)]
                struct UpperExp;

                #[derive(Display)]
                #[display("{POINTER:p}")]
                struct Pointer;

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", Display), "011");
                    assert_eq!(format!("{:03}", Debug), "011");
                    assert_eq!(format!("{:07}", Binary), "0001011");
                    assert_eq!(format!("{:07}", Octal), "0000013");
                    assert_eq!(format!("{:03}", LowerHex), "00b");
                    assert_eq!(format!("{:03}", UpperHex), "00B");
                    assert_eq!(format!("{:07}", LowerExp), "03.15e0");
                    assert_eq!(format!("{:07}", UpperExp), "03.15E0");
                    assert_eq!(format!("{:018}", Pointer), format!("{POINTER:018p}"));
                }
            }

            mod omitted {
                use super::*;

                mod on_modifiers {
                    use super::*;

                    const I32: i32 = 11;
                    const F64: f64 = 3.15;

                    #[derive(Display)]
                    #[display("{I32:x?}")]
                    struct LowerDebug;

                    #[derive(Display)]
                    #[display("{I32:X?}")]
                    struct UpperDebug;

                    #[derive(Display)]
                    #[display("{:^}", I32)]
                    struct Align;

                    #[derive(Display)]
                    #[display("{:+}", I32)]
                    struct Sign;

                    #[derive(Display)]
                    #[display("{:#b}", I32)]
                    struct Alternate;

                    #[derive(Display)]
                    #[display("{:0}", I32)]
                    struct ZeroPadded;

                    #[derive(Display)]
                    #[display("{:07}", I32)]
                    struct Width;

                    #[derive(Display)]
                    #[display("{:.1}", F64)]
                    struct Precision;

                    #[test]
                    fn assert() {
                        assert_eq!(format!("{:03}", LowerDebug), "b");
                        assert_eq!(format!("{:03}", UpperDebug), "B");
                        assert_eq!(format!("{:03}", Align), "11");
                        assert_eq!(format!("{:04}", Sign), "+11");
                        assert_eq!(format!("{:07}", Alternate), "0b1011");
                        assert_eq!(format!("{:07}", ZeroPadded), "11");
                        assert_eq!(format!("{:03}", Width), "0000011");
                        assert_eq!(format!("{:.3}", Precision), "3.1");
                    }
                }
            }
        }
    }

    mod single_field {
        use super::*;

        #[derive(Display)]
        struct Tuple(i32);

        #[derive(Binary)]
        struct Binary(i32);

        #[derive(Display)]
        struct Struct {
            field: i32,
        }

        #[derive(Octal)]
        struct Octal {
            field: i32,
        }

        #[test]
        fn assert() {
            assert_eq!(Tuple(0).to_string(), "0");
            assert_eq!(format!("{:b}", Binary(10)), "1010");
            assert_eq!(Struct { field: 0 }.to_string(), "0");
            assert_eq!(format!("{:o}", Octal { field: 10 }).to_string(), "12");
        }

        mod str {
            use super::*;

            #[derive(Display)]
            #[display("tuple")]
            struct Tuple(i32);

            #[derive(Display)]
            #[display("struct")]
            struct Struct {
                field: i32,
            }

            #[test]
            fn assert() {
                assert_eq!(Tuple(0).to_string(), "tuple");
                assert_eq!(Struct { field: 0 }.to_string(), "struct");
            }
        }

        mod interpolated {
            use super::*;

            #[derive(Display)]
            #[display("tuple: {_0} {}", _0)]
            struct Tuple(i32);

            #[derive(Display)]
            #[display("struct: {field} {}", field)]
            struct Struct {
                field: i32,
            }

            #[test]
            fn assert() {
                assert_eq!(Tuple(0).to_string(), "tuple: 0 0");
                assert_eq!(Struct { field: 0 }.to_string(), "struct: 0 0");
            }
        }

        mod transparency {
            use super::*;

            mod direct {
                use super::*;

                #[derive(Display)]
                struct TupleDisplay(i32);

                #[derive(Binary)]
                struct TupleBinary(i32);

                #[derive(Octal)]
                struct TupleOctal(i32);

                #[derive(LowerHex)]
                struct StructLowerHex {
                    field: i32,
                }

                #[derive(UpperHex)]
                struct StructUpperHex {
                    field: i32,
                }

                #[derive(LowerExp)]
                struct StructLowerExp {
                    field: f64,
                }

                #[derive(UpperExp)]
                struct StructUpperExp {
                    field: f64,
                }

                #[derive(Pointer)]
                struct StructPointer<'a> {
                    field: &'a i32,
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", TupleDisplay(7)), "007");
                    assert_eq!(format!("{:07b}", TupleBinary(7)), "0000111");
                    assert_eq!(format!("{:03o}", TupleOctal(9)), "011");
                    assert_eq!(format!("{:03x}", StructLowerHex { field: 42 }), "02a");
                    assert_eq!(format!("{:03X}", StructUpperHex { field: 42 }), "02A");
                    assert_eq!(
                        format!("{:07e}", StructLowerExp { field: 42.0 }),
                        "004.2e1",
                    );
                    assert_eq!(
                        format!("{:07E}", StructUpperExp { field: 42.0 }),
                        "004.2E1",
                    );
                    let a = 42;
                    assert_eq!(
                        format!("{:018p}", StructPointer { field: &a }),
                        format!("{:018p}", &a),
                    );
                }
            }

            mod interpolated {
                use super::*;

                #[derive(Display)]
                #[display("{_0}")]
                struct TupleDisplay(i32);

                #[derive(Display)]
                #[display("{_0:?}")]
                struct TupleDebug(i32);

                #[derive(Display)]
                #[display("{:b}", _0)]
                struct TupleBinary(i32);

                #[derive(Display)]
                #[display("{0:o}", _0)]
                struct TupleOctal(i32);

                #[derive(Display)]
                #[display("{field:x}")]
                struct StructLowerHex {
                    field: i32,
                }

                #[derive(Display)]
                #[display("{:X}", field)]
                struct StructUpperHex {
                    field: i32,
                }

                #[derive(Display)]
                #[display("{field:e}")]
                struct StructLowerExp {
                    field: f64,
                }

                #[derive(Display)]
                #[display("{named:E}", named = field)]
                struct StructUpperExp {
                    field: f64,
                }

                #[derive(Display)]
                #[display("{field:p}")]
                struct StructPointer<'a> {
                    field: &'a i32,
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", TupleDisplay(7)), "007");
                    assert_eq!(format!("{:03}", TupleDebug(8)), "008");
                    assert_eq!(format!("{:07}", TupleBinary(7)), "0000111");
                    assert_eq!(format!("{:03}", TupleOctal(9)), "011");
                    assert_eq!(format!("{:03}", StructLowerHex { field: 42 }), "02a");
                    assert_eq!(format!("{:03}", StructUpperHex { field: 42 }), "02A");
                    assert_eq!(
                        format!("{:07}", StructLowerExp { field: 42.0 }),
                        "004.2e1",
                    );
                    assert_eq!(
                        format!("{:07}", StructUpperExp { field: 42.0 }),
                        "004.2E1",
                    );
                    let a = 42;
                    assert_eq!(
                        format!("{:018}", StructPointer { field: &a }),
                        format!("{:018p}", &a),
                    );
                }
            }

            mod suppressed {
                use super::*;

                #[derive(Display)]
                #[display("{}", format_args!("{_0}"))]
                struct TupleDisplay(i32);

                #[derive(Display)]
                #[display("{}", format_args!("{_0:?}"))]
                struct TupleDebug(i32);

                #[derive(Display)]
                #[display("{}", format_args!("{_0:b}"))]
                struct TupleBinary(i32);

                #[derive(Display)]
                #[display("{}", format_args!("{_0:o}"))]
                struct TupleOctal(i32);

                #[derive(Display)]
                #[display("{}", format_args!("{field:x}"))]
                struct StructLowerHex {
                    field: i32,
                }

                #[derive(Display)]
                #[display("{}", format_args!("{field:X}"))]
                struct StructUpperHex {
                    field: i32,
                }

                #[derive(Display)]
                #[display("{}", format_args!("{field:e}"))]
                struct StructLowerExp {
                    field: f64,
                }

                #[derive(Display)]
                #[display("{}", format_args!("{field:E}"))]
                struct StructUpperExp {
                    field: f64,
                }

                #[derive(Display)]
                #[display("{}", format_args!("{field:p}", field = *field))]
                struct StructPointer<'a> {
                    field: &'a i32,
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", TupleDisplay(7)), "7");
                    assert_eq!(format!("{:03}", TupleDebug(8)), "8");
                    assert_eq!(format!("{:07}", TupleBinary(7)), "111");
                    assert_eq!(format!("{:03}", TupleOctal(9)), "11");
                    assert_eq!(format!("{:03}", StructLowerHex { field: 42 }), "2a");
                    assert_eq!(format!("{:03}", StructUpperHex { field: 42 }), "2A");
                    assert_eq!(
                        format!("{:07}", StructLowerExp { field: 42.0 }),
                        "4.2e1",
                    );
                    assert_eq!(
                        format!("{:07}", StructUpperExp { field: 42.0 }),
                        "4.2E1",
                    );
                    let a = 42;
                    assert_eq!(
                        format!("{:018}", StructPointer { field: &a }),
                        format!("{:p}", &a),
                    );
                }
            }

            mod omitted {
                use super::*;

                mod on_modifiers {
                    use super::*;

                    #[derive(Display)]
                    #[display("{_0:x?}")]
                    struct LowerDebug(i32);

                    #[derive(Display)]
                    #[display("{_0:X?}")]
                    struct UpperDebug(i32);

                    #[derive(Display)]
                    #[display("{:^}", _0)]
                    struct Align(i32);

                    #[derive(Display)]
                    #[display("{:+}", _0)]
                    struct Sign(i32);

                    #[derive(Display)]
                    #[display("{:#b}", _0)]
                    struct Alternate(i32);

                    #[derive(Display)]
                    #[display("{:0}", _0)]
                    struct ZeroPadded(i32);

                    #[derive(Display)]
                    #[display("{:07}", _0)]
                    struct Width(i32);

                    #[derive(Display)]
                    #[display("{:.5}", _0)]
                    struct Precision(f64);

                    #[test]
                    fn assert() {
                        assert_eq!(format!("{:03}", LowerDebug(7)), "7");
                        assert_eq!(format!("{:03}", UpperDebug(8)), "8");
                        assert_eq!(format!("{:03}", Align(5)), "5");
                        assert_eq!(format!("{:03}", Sign(5)), "+5");
                        assert_eq!(format!("{:07}", Alternate(5)), "0b101");
                        assert_eq!(format!("{:07}", ZeroPadded(-5)), "-5");
                        assert_eq!(format!("{:03}", Width(5)), "0000005");
                        assert_eq!(format!("{:.3}", Precision(1.23456789)), "1.23457");
                    }
                }
            }
        }

        mod r#unsized {
            use core::ptr;

            use super::*;

            #[derive(Display)]
            struct Tuple(str);

            #[derive(Display)]
            struct Struct {
                tail: str,
            }

            #[test]
            fn assert() {
                let dat = "14";

                let t =
                    unsafe { &*(ptr::addr_of!(*dat) as *const [i32] as *const Tuple) };
                assert_eq!(t.to_string(), "14");
                let s =
                    unsafe { &*(ptr::addr_of!(*dat) as *const [i32] as *const Struct) };
                assert_eq!(s.to_string(), "14");
            }

            mod interpolated {
                use core::ptr;

                use super::*;

                #[derive(Display)]
                #[display("{}.", _0)]
                struct Tuple1(str);

                #[derive(Display)]
                #[display("{_0}.")]
                struct Tuple2(str);

                #[derive(Display)]
                #[display("{}.", tail)]
                struct Struct1 {
                    tail: str,
                }

                #[derive(Display)]
                #[display("{tail}.")]
                struct Struct2 {
                    tail: str,
                }

                #[test]
                fn assert() {
                    let dat = "14";

                    let t1 = unsafe {
                        &*(ptr::addr_of!(*dat) as *const [i32] as *const Tuple1)
                    };
                    assert_eq!(t1.to_string(), "14.");
                    let t2 = unsafe {
                        &*(ptr::addr_of!(*dat) as *const [i32] as *const Tuple2)
                    };
                    assert_eq!(t2.to_string(), "14.");
                    let s1 = unsafe {
                        &*(ptr::addr_of!(*dat) as *const [i32] as *const Struct1)
                    };
                    assert_eq!(s1.to_string(), "14.");
                    let s2 = unsafe {
                        &*(ptr::addr_of!(*dat) as *const [i32] as *const Struct2)
                    };
                    assert_eq!(s2.to_string(), "14.");
                }
            }
        }

        #[cfg(nightly)]
        mod never {
            use super::*;

            #[derive(Display)]
            struct Tuple(!);

            #[derive(Display)]
            struct Struct {
                field: !,
            }
        }
    }

    mod multi_field {
        use super::*;

        mod str {
            use super::*;

            #[derive(Display)]
            #[display("tuple")]
            struct Tuple(i32, i32);

            #[derive(Display)]
            #[display("struct")]
            struct Struct {
                field1: i32,
                field2: i32,
            }

            #[test]
            fn assert() {
                assert_eq!(Tuple(1, 2).to_string(), "tuple");
                assert_eq!(
                    Struct {
                        field1: 1,
                        field2: 2,
                    }
                    .to_string(),
                    "struct",
                );
            }
        }

        mod interpolated {
            use super::*;

            #[derive(Display)]
            #[display(
                "{_0} {ident} {_1} {} {}",
                _1, _0 + _1, ident = 123, _1 = _0,
            )]
            struct Tuple(i32, i32);

            #[derive(Display)]
            #[display(
                "{field1} {ident} {field2} {} {}",
                field2, field1 + field2, ident = 123, field2 = field1,
            )]
            struct Struct {
                field1: i32,
                field2: i32,
            }

            #[test]
            fn assert() {
                assert_eq!(Tuple(1, 2).to_string(), "1 123 1 2 3");
                assert_eq!(
                    Struct {
                        field1: 1,
                        field2: 2,
                    }
                    .to_string(),
                    "1 123 1 2 3",
                );
            }
        }

        mod transparency {
            use super::*;

            mod interpolated {
                use super::*;

                #[derive(Display)]
                #[display("{_0}")]
                struct TupleDisplay(i32, u64);

                #[derive(Display)]
                #[display("{:?}", _1)]
                struct TupleDebug(i32, u64);

                #[derive(Display)]
                #[display("{0:b}", _1)]
                struct TupleBinary(i32, u64);

                #[derive(Display)]
                #[display("{named:o}", named = _0)]
                struct TupleOctal(i32, u64);

                #[derive(Display)]
                #[display("{b:x}")]
                struct StructLowerHex {
                    a: i32,
                    b: u64,
                }

                #[derive(Display)]
                #[display("{:X}", a)]
                struct StructUpperHex {
                    a: i32,
                    b: u64,
                }

                #[derive(Display)]
                #[display("{a:e}")]
                struct StructLowerExp {
                    a: f64,
                    b: f32,
                }

                #[derive(Display)]
                #[display("{:E}", b)]
                struct StructUpperExp {
                    a: f64,
                    b: f32,
                }

                #[derive(Display)]
                #[display("{b:p}")]
                struct StructPointer<'a> {
                    a: &'a i32,
                    b: &'a i32,
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", TupleDisplay(7, 8)), "007");
                    assert_eq!(format!("{:03}", TupleDebug(7, 8)), "008");
                    assert_eq!(format!("{:07}", TupleBinary(6, 7)), "0000111");
                    assert_eq!(format!("{:03}", TupleOctal(9, 10)), "011");
                    assert_eq!(
                        format!("{:03}", StructLowerHex { a: 41, b: 42 }),
                        "02a"
                    );
                    assert_eq!(
                        format!("{:03}", StructUpperHex { a: 42, b: 43 }),
                        "02A"
                    );
                    assert_eq!(
                        format!("{:07}", StructLowerExp { a: 42.0, b: 43.0 }),
                        "004.2e1",
                    );
                    assert_eq!(
                        format!("{:07}", StructUpperExp { a: 41.0, b: 42.0 }),
                        "004.2E1",
                    );
                    let (a, b) = (42, 43);
                    assert_eq!(
                        format!("{:018}", StructPointer { a: &a, b: &b }),
                        format!("{:018p}", &b),
                    );
                }
            }
        }

        mod r#unsized {
            use super::*;

            mod interpolated {
                use core::ptr;

                use super::*;

                #[derive(Display)]
                #[display("{}.{}", _0, _1)]
                struct Tuple1(char, str);

                #[derive(Display)]
                #[display("{_0}.{_1}")]
                struct Tuple2(char, str);

                #[derive(Display)]
                #[display("{}.{}", head, tail)]
                struct Struct1 {
                    head: char,
                    tail: str,
                }

                #[derive(Display)]
                #[display("{head}.{tail}")]
                struct Struct2 {
                    head: char,
                    tail: str,
                }

                #[test]
                fn assert() {
                    let dat = [51i32, 3028017];

                    let t1 = unsafe {
                        &*(ptr::addr_of!(dat) as *const [i32] as *const Tuple1)
                    };
                    assert_eq!(t1.to_string(), "3.14");
                    let t2 = unsafe {
                        &*(ptr::addr_of!(dat) as *const [i32] as *const Tuple2)
                    };
                    assert_eq!(t2.to_string(), "3.14");
                    let s1 = unsafe {
                        &*(ptr::addr_of!(dat) as *const [i32] as *const Struct1)
                    };
                    assert_eq!(s1.to_string(), "3.14");
                    let s2 = unsafe {
                        &*(ptr::addr_of!(dat) as *const [i32] as *const Struct2)
                    };
                    assert_eq!(s2.to_string(), "3.14");
                }
            }
        }

        #[cfg(nightly)]
        mod never {
            use super::*;

            #[derive(Display)]
            #[display("{_0}")]
            struct Tuple(i32, !);

            #[derive(Display)]
            #[display("{field}")]
            struct Struct {
                field: !,
                other: i32,
            }
        }
    }
}

mod enums {
    use super::*;

    mod no_variants {
        use super::*;

        #[derive(Display)]
        enum Void {}

        const fn assert<T: Display>() {}
        const _: () = assert::<Void>();
    }

    mod unit_variant {
        use super::*;

        #[derive(Display)]
        enum Enum {
            Unit,
            r#RawUnit,
            Unnamed(),
            Named {},
            #[display("STR_UNIT")]
            StrUnit,
            #[display("STR_UNNAMED")]
            StrUnnamed(),
            #[display("STR_NAMED")]
            StrNamed {},
        }

        #[test]
        fn assert() {
            assert_eq!(Enum::Unit.to_string(), "Unit");
            assert_eq!(Enum::r#RawUnit.to_string(), "RawUnit");
            assert_eq!(Enum::Unnamed().to_string(), "Unnamed");
            assert_eq!(Enum::Named {}.to_string(), "Named");
            assert_eq!(Enum::StrUnit.to_string(), "STR_UNIT");
            assert_eq!(Enum::StrUnnamed().to_string(), "STR_UNNAMED");
            assert_eq!(Enum::StrNamed {}.to_string(), "STR_NAMED");
        }

        mod transparency {
            use super::*;

            mod interpolated {
                use super::*;

                const I32: i32 = 11;
                const F64: f64 = 3.15;
                const POINTER: &f64 = &3.15;

                #[derive(Display)]
                enum Unit {
                    #[display("{I32}")]
                    Display,
                    #[display("{I32:?}")]
                    Debug,
                    #[display("{:b}", I32)]
                    Binary,
                    #[display("{0:o}", I32)]
                    Octal,
                    #[display("{I32:x}")]
                    LowerHex,
                    #[display("{:X}", I32)]
                    UpperHex,
                    #[display("{F64:e}")]
                    LowerExp,
                    #[display("{named:E}", named = F64)]
                    UpperExp,
                    #[display("{POINTER:p}")]
                    Pointer,
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", Unit::Display), "011");
                    assert_eq!(format!("{:03}", Unit::Debug), "011");
                    assert_eq!(format!("{:07}", Unit::Binary), "0001011");
                    assert_eq!(format!("{:07}", Unit::Octal), "0000013");
                    assert_eq!(format!("{:03}", Unit::LowerHex), "00b");
                    assert_eq!(format!("{:03}", Unit::UpperHex), "00B");
                    assert_eq!(format!("{:07}", Unit::LowerExp), "03.15e0");
                    assert_eq!(format!("{:07}", Unit::UpperExp), "03.15E0");
                    assert_eq!(
                        format!("{:018}", Unit::Pointer),
                        format!("{POINTER:018p}"),
                    );
                }
            }

            mod omitted {
                use super::*;

                mod on_modifiers {
                    use super::*;

                    const I32: i32 = 11;
                    const F64: f64 = 3.15;

                    #[derive(Display)]
                    enum Unit {
                        #[display("{I32:x?}")]
                        LowerDebug,
                        #[display("{I32:X?}")]
                        UpperDebug,
                        #[display("{:^}", I32)]
                        Align,
                        #[display("{:+}", I32)]
                        Sign,
                        #[display("{:#b}", I32)]
                        Alternate,
                        #[display("{:0}", I32)]
                        ZeroPadded,
                        #[display("{:07}", I32)]
                        Width,
                        #[display("{:.1}", F64)]
                        Precision,
                    }

                    #[test]
                    fn assert() {
                        assert_eq!(format!("{:03}", Unit::LowerDebug), "b");
                        assert_eq!(format!("{:03}", Unit::UpperDebug), "B");
                        assert_eq!(format!("{:03}", Unit::Align), "11");
                        assert_eq!(format!("{:04}", Unit::Sign), "+11");
                        assert_eq!(format!("{:07}", Unit::Alternate), "0b1011");
                        assert_eq!(format!("{:07}", Unit::ZeroPadded), "11");
                        assert_eq!(format!("{:03}", Unit::Width), "0000011");
                        assert_eq!(format!("{:.3}", Unit::Precision), "3.1");
                    }
                }
            }
        }
    }

    mod single_field_variant {
        use super::*;

        #[derive(Display)]
        enum Enum {
            Unnamed(i32),
            Named {
                field: i32,
            },
            #[display("unnamed")]
            StrUnnamed(i32),
            #[display("named")]
            StrNamed {
                field: i32,
            },
            #[display("{_0} {}", _0)]
            InterpolatedUnnamed(i32),
            #[display("{field} {}", field)]
            InterpolatedNamed {
                field: i32,
            },
        }

        #[test]
        fn assert() {
            assert_eq!(Enum::Unnamed(1).to_string(), "1");
            assert_eq!(Enum::Named { field: 1 }.to_string(), "1");
            assert_eq!(Enum::StrUnnamed(1).to_string(), "unnamed");
            assert_eq!(Enum::StrNamed { field: 1 }.to_string(), "named");
            assert_eq!(Enum::InterpolatedUnnamed(1).to_string(), "1 1");
            assert_eq!(Enum::InterpolatedNamed { field: 1 }.to_string(), "1 1");
        }

        mod transparency {
            use super::*;

            mod direct {
                use super::*;

                #[derive(Display)]
                enum Display {
                    A(i32),
                    B { field: u8 },
                }

                #[derive(Binary)]
                enum Binary {
                    A(i32),
                    B { field: u8 },
                }

                #[derive(Octal)]
                enum Octal {
                    A(i32),
                    B { field: u8 },
                }

                #[derive(LowerHex)]
                enum LowerHex {
                    A(i32),
                    B { field: u8 },
                }

                #[derive(UpperHex)]
                enum UpperHex {
                    A(i32),
                    B { field: u8 },
                }

                #[derive(LowerExp)]
                enum LowerExp {
                    A(f64),
                    B { field: f32 },
                }

                #[derive(UpperExp)]
                enum UpperExp {
                    A(f64),
                    B { field: f32 },
                }

                #[derive(Pointer)]
                enum Pointer<'a> {
                    A(&'a i32),
                    B { field: &'a u8 },
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", Display::A(7)), "007");
                    assert_eq!(format!("{:03}", Display::B { field: 8 }), "008");
                    assert_eq!(format!("{:07b}", Binary::A(7)), "0000111");
                    assert_eq!(format!("{:07b}", Binary::B { field: 8 }), "0001000");
                    assert_eq!(format!("{:03o}", Octal::A(9)), "011");
                    assert_eq!(format!("{:03o}", Octal::B { field: 10 }), "012");
                    assert_eq!(format!("{:03x}", LowerHex::A(42)), "02a");
                    assert_eq!(format!("{:03x}", LowerHex::B { field: 43 }), "02b");
                    assert_eq!(format!("{:03X}", UpperHex::A(42)), "02A");
                    assert_eq!(format!("{:03X}", UpperHex::B { field: 43 }), "02B");
                    assert_eq!(format!("{:07e}", LowerExp::A(42.0)), "004.2e1");
                    assert_eq!(
                        format!("{:07e}", LowerExp::B { field: 43.0 }),
                        "004.3e1",
                    );
                    assert_eq!(format!("{:07E}", UpperExp::A(42.0)), "004.2E1");
                    assert_eq!(
                        format!("{:07E}", UpperExp::B { field: 43.0 }),
                        "004.3E1",
                    );
                    let (a, b) = (7, 42);
                    assert_eq!(
                        format!("{:018p}", Pointer::A(&a)),
                        format!("{:018p}", &a),
                    );
                    assert_eq!(
                        format!("{:018p}", Pointer::B { field: &b }),
                        format!("{:018p}", &b),
                    );
                }
            }

            mod interpolated {
                use super::*;

                #[derive(Display)]
                enum Display {
                    #[display("{_0}")]
                    A(i32),
                    #[display("{}", field)]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum Debug {
                    #[display("{0:?}", _0)]
                    A(i32),
                    #[display("{named:?}", named = field)]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum Binary {
                    #[display("{_0:b}")]
                    A(i32),
                    #[display("{:b}", field)]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum Octal {
                    #[display("{_0:o}")]
                    A(i32),
                    #[display("{:o}", field)]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum LowerHex {
                    #[display("{_0:x}")]
                    A(i32),
                    #[display("{:x}", field)]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum UpperHex {
                    #[display("{_0:X}")]
                    A(i32),
                    #[display("{:X}", field)]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum LowerExp {
                    #[display("{:e}", _0)]
                    A(f64),
                    #[display("{field:e}")]
                    B { field: f32 },
                }

                #[derive(Display)]
                enum UpperExp {
                    #[display("{:E}", _0)]
                    A(f64),
                    #[display("{field:E}")]
                    B { field: f32 },
                }

                #[derive(Display)]
                enum Pointer<'a> {
                    #[display("{:p}", *_0)]
                    A(&'a i32),
                    #[display("{field:p}")]
                    B { field: &'a u8 },
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", Display::A(7)), "007");
                    assert_eq!(format!("{:03}", Display::B { field: 8 }), "008");
                    assert_eq!(format!("{:03}", Debug::A(8)), "008");
                    assert_eq!(format!("{:03}", Debug::B { field: 9 }), "009");
                    assert_eq!(format!("{:07}", Binary::A(7)), "0000111");
                    assert_eq!(format!("{:07}", Binary::B { field: 8 }), "0001000");
                    assert_eq!(format!("{:03}", Octal::A(9)), "011");
                    assert_eq!(format!("{:03}", Octal::B { field: 10 }), "012");
                    assert_eq!(format!("{:03}", LowerHex::A(42)), "02a");
                    assert_eq!(format!("{:03}", LowerHex::B { field: 43 }), "02b");
                    assert_eq!(format!("{:03}", UpperHex::A(42)), "02A");
                    assert_eq!(format!("{:03}", UpperHex::B { field: 43 }), "02B");
                    assert_eq!(format!("{:07}", LowerExp::A(42.0)), "004.2e1");
                    assert_eq!(
                        format!("{:07}", LowerExp::B { field: 43.0 }),
                        "004.3e1",
                    );
                    assert_eq!(format!("{:07}", UpperExp::A(42.0)), "004.2E1");
                    assert_eq!(
                        format!("{:07}", UpperExp::B { field: 43.0 }),
                        "004.3E1",
                    );
                    let (a, b) = (7, 42);
                    assert_eq!(
                        format!("{:018}", Pointer::A(&a)),
                        format!("{:018p}", &a),
                    );
                    assert_eq!(
                        format!("{:018}", Pointer::B { field: &b }),
                        format!("{:018p}", &b),
                    );
                }
            }

            mod suppressed {
                use super::*;

                #[derive(Display)]
                enum Display {
                    #[display("{}", format_args!("{_0}"))]
                    A(i32),
                    #[display("{}", format_args!("{}", field))]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum Debug {
                    #[display("{}", format_args!("{_0:?}"))]
                    A(i32),
                    #[display("{}", format_args!("{:?}", field))]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum Binary {
                    #[display("{}", format_args!("{_0:b}"))]
                    A(i32),
                    #[display("{}", format_args!("{:b}", field))]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum Octal {
                    #[display("{}", format_args!("{_0:o}"))]
                    A(i32),
                    #[display("{}", format_args!("{:o}", field))]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum LowerHex {
                    #[display("{}", format_args!("{_0:x}"))]
                    A(i32),
                    #[display("{}", format_args!("{:x}", field))]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum UpperHex {
                    #[display("{}", format_args!("{_0:X}"))]
                    A(i32),
                    #[display("{}", format_args!("{:X}", field))]
                    B { field: u8 },
                }

                #[derive(Display)]
                enum LowerExp {
                    #[display("{}", format_args!("{:e}", _0))]
                    A(f64),
                    #[display("{}", format_args!("{field:e}"))]
                    B { field: f32 },
                }

                #[derive(Display)]
                enum UpperExp {
                    #[display("{}", format_args!("{:E}", _0))]
                    A(f64),
                    #[display("{}", format_args!("{field:E}"))]
                    B { field: f32 },
                }

                #[derive(Display)]
                enum Pointer<'a> {
                    #[display("{}", format_args!("{:p}", *_0))]
                    A(&'a i32),
                    #[display("{}", format_args!("{field:p}", field = *field))]
                    B { field: &'a u8 },
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", Display::A(7)), "7");
                    assert_eq!(format!("{:03}", Display::B { field: 8 }), "8");
                    assert_eq!(format!("{:03}", Debug::A(8)), "8");
                    assert_eq!(format!("{:03}", Debug::B { field: 9 }), "9");
                    assert_eq!(format!("{:07}", Binary::A(7)), "111");
                    assert_eq!(format!("{:07}", Binary::B { field: 8 }), "1000");
                    assert_eq!(format!("{:03}", Octal::A(9)), "11");
                    assert_eq!(format!("{:03}", Octal::B { field: 10 }), "12");
                    assert_eq!(format!("{:03}", LowerHex::A(42)), "2a");
                    assert_eq!(format!("{:03}", LowerHex::B { field: 43 }), "2b");
                    assert_eq!(format!("{:03}", UpperHex::A(42)), "2A");
                    assert_eq!(format!("{:03}", UpperHex::B { field: 43 }), "2B");
                    assert_eq!(format!("{:07}", LowerExp::A(42.0)), "4.2e1");
                    assert_eq!(format!("{:07}", LowerExp::B { field: 43.0 }), "4.3e1");
                    assert_eq!(format!("{:07}", UpperExp::A(42.0)), "4.2E1");
                    assert_eq!(format!("{:07}", UpperExp::B { field: 43.0 }), "4.3E1");
                    let (a, b) = (7, 42);
                    assert_eq!(format!("{:018}", Pointer::A(&a)), format!("{:0p}", &a));
                    assert_eq!(
                        format!("{:018}", Pointer::B { field: &b }),
                        format!("{:p}", &b),
                    );
                }
            }
        }

        #[cfg(nightly)]
        mod never {
            use super::*;

            #[derive(Display)]
            enum Enum {
                Unnamed(!),
                Named { field: ! },
            }
        }
    }

    mod multi_field_variant {
        use super::*;

        #[derive(Display)]
        enum Enum {
            #[display("unnamed")]
            StrUnnamed(i32, i32),
            #[display("named")]
            StrNamed { field1: i32, field2: i32 },
            #[display(
                "{_0} {ident} {_1} {} {}",
                _1, _0 + _1, ident = 123, _1 = _0,
            )]
            InterpolatedUnnamed(i32, i32),
            #[display(
                "{field1} {ident} {field2} {} {}",
                field2, field1 + field2, ident = 123, field2 = field1,
            )]
            InterpolatedNamed { field1: i32, field2: i32 },
        }

        #[test]
        fn assert() {
            assert_eq!(Enum::StrUnnamed(1, 2).to_string(), "unnamed");
            assert_eq!(
                Enum::StrNamed {
                    field1: 1,
                    field2: 2,
                }
                .to_string(),
                "named",
            );
            assert_eq!(Enum::InterpolatedUnnamed(1, 2).to_string(), "1 123 1 2 3");
            assert_eq!(
                Enum::InterpolatedNamed {
                    field1: 1,
                    field2: 2,
                }
                .to_string(),
                "1 123 1 2 3",
            );
        }

        mod transparency {
            use super::*;

            mod interpolated {
                use super::*;

                #[derive(Display)]
                enum Display {
                    #[display("{_0}")]
                    A(i32, i64),
                    #[display("{}", b)]
                    B { a: u8, b: i32 },
                }

                #[derive(Display)]
                enum Debug {
                    #[display("{0:?}", _1)]
                    A(i32, i64),
                    #[display("{named:?}", named = a)]
                    B { a: u8, b: i32 },
                }

                #[derive(Display)]
                enum Binary {
                    #[display("{_0:b}")]
                    A(i32, i64),
                    #[display("{:b}", b)]
                    B { a: u8, b: i32 },
                }

                #[derive(Display)]
                enum Octal {
                    #[display("{_0:o}")]
                    A(i32, i64),
                    #[display("{:o}", b)]
                    B { a: u8, b: i32 },
                }

                #[derive(Display)]
                enum LowerHex {
                    #[display("{_0:x}")]
                    A(i32, i64),
                    #[display("{:x}", b)]
                    B { a: u8, b: i32 },
                }

                #[derive(Display)]
                enum UpperHex {
                    #[display("{_0:X}")]
                    A(i32, i64),
                    #[display("{:X}", b)]
                    B { a: u8, b: i32 },
                }

                #[derive(Display)]
                enum LowerExp {
                    #[display("{:e}", _1)]
                    A(f64, f32),
                    #[display("{a:e}")]
                    B { a: f64, b: f32 },
                }

                #[derive(Display)]
                enum UpperExp {
                    #[display("{:E}", _1)]
                    A(f64, f32),
                    #[display("{a:E}")]
                    B { a: f64, b: f32 },
                }

                #[derive(Display)]
                enum Pointer<'a> {
                    #[display("{:p}", *_1)]
                    A(&'a f64, &'a f32),
                    #[display("{a:p}")]
                    B { a: &'a f64, b: &'a f32 },
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", Display::A(7, 8)), "007");
                    assert_eq!(format!("{:03}", Display::B { a: 7, b: 8 }), "008");
                    assert_eq!(format!("{:03}", Debug::A(7, 8)), "008");
                    assert_eq!(format!("{:03}", Debug::B { a: 7, b: 8 }), "007");
                    assert_eq!(format!("{:07}", Binary::A(7, 8)), "0000111");
                    assert_eq!(format!("{:07}", Binary::B { a: 7, b: 8 }), "0001000");
                    assert_eq!(format!("{:03}", Octal::A(9, 10)), "011");
                    assert_eq!(format!("{:03}", Octal::B { a: 9, b: 10 }), "012");
                    assert_eq!(format!("{:03}", LowerHex::A(42, 41)), "02a");
                    assert_eq!(format!("{:03}", LowerHex::B { a: 42, b: 43 }), "02b");
                    assert_eq!(format!("{:03}", UpperHex::A(42, 41)), "02A");
                    assert_eq!(format!("{:03}", UpperHex::B { a: 42, b: 43 }), "02B");
                    assert_eq!(format!("{:07}", LowerExp::A(41.0, 42.0)), "004.2e1");
                    assert_eq!(
                        format!("{:07}", LowerExp::B { a: 43.0, b: 52.0 }),
                        "004.3e1",
                    );
                    assert_eq!(format!("{:07}", UpperExp::A(41.0, 42.0)), "004.2E1");
                    assert_eq!(
                        format!("{:07}", UpperExp::B { a: 43.0, b: 52.0 }),
                        "004.3E1",
                    );
                    let (a, b) = (8.3, 42.1);
                    assert_eq!(
                        format!("{:018}", Pointer::A(&7.0, &a)),
                        format!("{:018p}", &a),
                    );
                    assert_eq!(
                        format!("{:018}", Pointer::B { a: &b, b: &43.3 }),
                        format!("{:018p}", &b),
                    );
                }
            }
        }

        #[cfg(nightly)]
        mod never {
            use super::*;

            #[derive(Display)]
            enum Enum {
                #[display("{_0}")]
                Unnamed(i32, !),
                #[display("{field}")]
                Named { field: !, other: i32 },
            }
        }

        mod shared_format {
            use super::*;

            mod single {
                use super::*;

                #[derive(Display)]
                #[display("Variant: {_variant}")]
                enum Enum {
                    #[display("A {_0}")]
                    A(i32),
                    #[display("B {}", field)]
                    B {
                        field: i32,
                    },
                    C,
                    #[display("D {_0} {}", _1)]
                    D(i8, u8),
                }

                #[test]
                fn assert() {
                    assert_eq!(Enum::A(1).to_string(), "Variant: A 1");
                    assert_eq!(Enum::B { field: 2 }.to_string(), "Variant: B 2");
                    assert_eq!(Enum::C.to_string(), "Variant: C");
                    assert_eq!(Enum::D(1, 2).to_string(), "Variant: D 1 2");
                }
            }

            mod transparent {
                use super::*;

                #[derive(Display)]
                #[display("{_variant}")]
                enum Enum {
                    #[display("A {_0}")]
                    A(i32),
                    #[display("B {}", field)]
                    B {
                        field: i32,
                    },
                    C,
                    #[display("D {_0} {}", _1)]
                    D(i8, u8),
                    #[display("{_0:b}")]
                    TransparentBinary(i32),
                }

                #[test]
                fn assert() {
                    assert_eq!(Enum::A(1).to_string(), "A 1");
                    assert_eq!(Enum::B { field: 2 }.to_string(), "B 2");
                    assert_eq!(Enum::C.to_string(), "C");
                    assert_eq!(Enum::D(1, 2).to_string(), "D 1 2");
                    assert_eq!(
                        format!("{:08}", Enum::TransparentBinary(4)),
                        "00000100",
                    );
                }
            }

            mod multiple {
                use super::*;

                #[derive(Display)]
                #[display("{_variant} Variant: {_variant} {}", _variant)]
                enum Enum {
                    #[display("A {_0}")]
                    A(i32),
                    #[display("B {}", field)]
                    B {
                        field: i32,
                    },
                    C,
                    #[display("D {_0} {}", _1)]
                    D(i8, u8),
                }

                #[test]
                fn assert() {
                    assert_eq!(Enum::A(1).to_string(), "A 1 Variant: A 1 A 1");
                    assert_eq!(
                        Enum::B { field: 2 }.to_string(),
                        "B 2 Variant: B 2 B 2",
                    );
                    assert_eq!(Enum::C.to_string(), "C Variant: C C");
                    assert_eq!(Enum::D(1, 2).to_string(), "D 1 2 Variant: D 1 2 D 1 2",);
                }
            }

            mod none {
                use super::*;

                /// Make sure that variant-specific bounds are not added if `_variant` is not used.
                struct NoDisplay;

                #[derive(Display)]
                #[display("Variant")]
                enum Enum<T> {
                    #[display("A {_0}")]
                    A(i32),
                    #[display("B {}", field)]
                    B {
                        field: i32,
                    },
                    C,
                    #[display("D {_0} {}", _1)]
                    D(i8, u8),
                    E {
                        a: u8,
                        b: i8,
                    },
                    X(T),
                }

                #[test]
                fn assert() {
                    assert_eq!(Enum::<NoDisplay>::A(1).to_string(), "A 1");
                    assert_eq!(Enum::<NoDisplay>::B { field: 2 }.to_string(), "B 2",);
                    assert_eq!(Enum::<NoDisplay>::C.to_string(), "Variant");
                    assert_eq!(Enum::<NoDisplay>::D(1, 2).to_string(), "D 1 2");
                    assert_eq!(
                        Enum::<NoDisplay>::E { a: 2, b: 1 }.to_string(),
                        "Variant"
                    );
                    assert_eq!(Enum::<NoDisplay>::X(NoDisplay).to_string(), "Variant");
                }
            }

            mod use_field {
                use super::*;

                #[derive(Display)]
                #[display("Variant {_0}")]
                enum Enum<T> {
                    A(i32),
                    B(&'static str),
                    #[display("D {_0} {}", _1)]
                    D(i8, u8),
                    E(u8, i8),
                    X(T),
                }

                #[test]
                fn assert() {
                    assert_eq!(Enum::<u8>::A(1).to_string(), "Variant 1");
                    assert_eq!(Enum::<u8>::B("abc").to_string(), "Variant abc");
                    assert_eq!(Enum::<u8>::D(1, 2).to_string(), "D 1 2");
                    assert_eq!(Enum::<u8>::E(2, 1).to_string(), "Variant 2");
                    assert_eq!(Enum::<u8>::X(9).to_string(), "Variant 9");
                }
            }

            mod only_field {
                use super::*;

                /// Make sure that top-level-specific bounds are not added if a field is not used.
                struct NoDisplay;

                #[derive(Display)]
                #[display("{_0}")]
                enum Enum<X, Y> {
                    #[display("A")]
                    A(i32),
                    #[display("B")]
                    B(&'static str),
                    #[display("D {_0} {}", _1)]
                    D(i8, u8),
                    E(u8, i8),
                    #[display("X")]
                    X(X),
                    Y(Y),
                }

                #[test]
                fn assert() {
                    assert_eq!(Enum::<NoDisplay, u8>::A(1).to_string(), "A");
                    assert_eq!(Enum::<NoDisplay, u8>::B("abc").to_string(), "B");
                    assert_eq!(Enum::<NoDisplay, u8>::D(1, 2).to_string(), "D 1 2");
                    assert_eq!(Enum::<NoDisplay, u8>::E(2, 1).to_string(), "2");
                    assert_eq!(Enum::<NoDisplay, u8>::X(NoDisplay).to_string(), "X");
                    assert_eq!(Enum::<NoDisplay, u8>::Y(9).to_string(), "9");
                }
            }

            mod only_multiple_field {
                use super::*;

                /// Make sure that top-level-specific bounds are not added if a field is not used.
                struct NoDisplay;

                #[derive(Display)]
                #[display("{_0} & {_1}")]
                enum Enum<X, Y> {
                    #[display("A")]
                    A(i32),
                    #[display("B")]
                    B(&'static str),
                    #[display("D {_0} {}", _1)]
                    D(i8, u8),
                    E(u8, i8),
                    #[display("X")]
                    X(X),
                    Y(Y, i8),
                }

                #[test]
                fn assert() {
                    assert_eq!(Enum::<NoDisplay, u8>::A(1).to_string(), "A");
                    assert_eq!(Enum::<NoDisplay, u8>::B("abc").to_string(), "B");
                    assert_eq!(Enum::<NoDisplay, u8>::D(1, 2).to_string(), "D 1 2");
                    assert_eq!(Enum::<NoDisplay, u8>::E(2, 1).to_string(), "2 & 1");
                    assert_eq!(Enum::<NoDisplay, u8>::X(NoDisplay).to_string(), "X");
                    assert_eq!(Enum::<NoDisplay, u8>::Y(9, 10).to_string(), "9 & 10");
                }
            }

            mod use_field_and_variant {
                use super::*;

                #[derive(Display)]
                #[display("Variant {_variant} {}", _0)]
                enum Enum<T> {
                    #[display("A")]
                    A(i32),
                    #[display("B")]
                    B(&'static str),
                    #[display("D {_0} {}", _1)]
                    D(i8, u8),
                    #[display("X")]
                    X(T),
                    Y(T),
                }

                #[test]
                fn assert() {
                    assert_eq!(Enum::<u8>::A(1).to_string(), "Variant A 1");
                    assert_eq!(Enum::<u8>::B("abc").to_string(), "Variant B abc");
                    assert_eq!(Enum::<u8>::D(1, 2).to_string(), "Variant D 1 2 1");
                    assert_eq!(Enum::<u8>::X(9).to_string(), "Variant X 9");
                    assert_eq!(Enum::<u8>::Y(9).to_string(), "Variant 9 9");
                }
            }

            mod as_debug {
                use super::*;

                #[derive(Debug, Display)]
                #[display("{self:?}")]
                enum Enum {
                    #[display("A {_0}")]
                    A(i32),
                    #[display("B {}", field)]
                    B {
                        field: i32,
                    },
                    C,
                    #[display("D {_0} {}", _1)]
                    D(i8, u8),
                    E {
                        a: u8,
                        b: i8,
                    },
                }

                #[test]
                fn assert() {
                    assert_eq!(Enum::A(1).to_string(), "A 1");
                    assert_eq!(Enum::B { field: 2 }.to_string(), "B 2");
                    assert_eq!(Enum::C.to_string(), "C");
                    assert_eq!(Enum::D(1, 2).to_string(), "D 1 2");
                    assert_eq!(Enum::E { a: 2, b: 1 }.to_string(), "E { a: 2, b: 1 }");
                }
            }

            mod pointer {
                use super::*;

                #[derive(Display)]
                #[display("Pointer {_0:p} {_variant} {_0:p}")]
                enum Pointer<'a> {
                    #[display("A")]
                    A(&'a f64),
                    #[display("B")]
                    B(&'a f32),
                }
                #[test]
                fn assert() {
                    let (a, b) = (8.3, 42.1);
                    assert_eq!(
                        Pointer::A(&a).to_string(),
                        format!("Pointer {0:p} A {0:p}", &a),
                    );
                    assert_eq!(
                        Pointer::B(&b).to_string(),
                        format!("Pointer {0:p} B {0:p}", &b),
                    );
                }
            }
        }
    }
}

mod generic {
    use super::*;

    trait Bound {}

    impl Bound for () {}

    fn display_bound<T: Bound>(_: &T) -> &'static str {
        "()"
    }

    #[derive(Display)]
    #[display("Generic {}", field)]
    struct NamedGenericStruct<T> {
        field: T,
    }
    #[test]
    fn named_generic_struct() {
        assert_eq!(NamedGenericStruct { field: 1 }.to_string(), "Generic 1");
    }

    #[derive(Display)]
    #[display("Generic {field}")]
    struct InterpolatedNamedGenericStruct<T> {
        field: T,
    }
    #[test]
    fn interpolated_named_generic_struct() {
        assert_eq!(
            InterpolatedNamedGenericStruct { field: 1 }.to_string(),
            "Generic 1",
        );
    }

    #[derive(Display)]
    #[display("Generic {field:<>width$.prec$} {field}")]
    struct InterpolatedNamedGenericStructWidthPrecision<T> {
        field: T,
        width: usize,
        prec: usize,
    }
    #[test]
    fn interpolated_named_generic_struct_width_precision() {
        assert_eq!(
            InterpolatedNamedGenericStructWidthPrecision {
                field: 1.2345,
                width: 9,
                prec: 2,
            }
            .to_string(),
            "Generic <<<<<1.23 1.2345",
        );
    }

    #[derive(Display)]
    struct AutoNamedGenericStruct<T> {
        field: T,
    }
    #[test]
    fn auto_named_generic_struct() {
        assert_eq!(AutoNamedGenericStruct { field: 1 }.to_string(), "1");
    }

    #[derive(Display)]
    #[display("{alias}", alias = field)]
    struct AliasedNamedGenericStruct<T> {
        field: T,
    }
    #[test]
    fn aliased_named_generic_struct() {
        assert_eq!(AliasedNamedGenericStruct { field: 1 }.to_string(), "1");
    }

    #[derive(Display)]
    #[display("{field1}", field1 = field2)]
    struct AliasedFieldNamedGenericStruct<T> {
        field1: T,
        field2: i32,
    }
    #[test]
    fn aliased_field_named_generic_struct() {
        assert_eq!(
            AliasedFieldNamedGenericStruct {
                field1: (),
                field2: 1,
            }
            .to_string(),
            "1",
        );
    }

    #[derive(Display)]
    #[display("Generic {}", _0)]
    struct UnnamedGenericStruct<T>(T);
    #[test]
    fn unnamed_generic_struct() {
        assert_eq!(UnnamedGenericStruct(2).to_string(), "Generic 2");
    }

    #[derive(Display)]
    #[display("Generic {_0}")]
    struct InterpolatedUnnamedGenericStruct<T>(T);
    #[test]
    fn interpolated_unnamed_generic_struct() {
        assert_eq!(InterpolatedUnnamedGenericStruct(2).to_string(), "Generic 2");
    }

    #[derive(Display)]
    struct AutoUnnamedGenericStruct<T>(T);
    #[test]
    fn auto_unnamed_generic_struct() {
        assert_eq!(AutoUnnamedGenericStruct(2).to_string(), "2");
    }

    #[derive(Display)]
    #[display("{alias}", alias = _0)]
    struct AliasedUnnamedGenericStruct<T>(T);
    #[test]
    fn aliased_unnamed_generic_struct() {
        assert_eq!(AliasedUnnamedGenericStruct(2).to_string(), "2");
    }

    #[derive(Display)]
    #[display("{_0}", _0 = _1)]
    struct AliasedFieldUnnamedGenericStruct<T>(T, i32);
    #[test]
    fn aliased_field_unnamed_generic_struct() {
        assert_eq!(AliasedFieldUnnamedGenericStruct((), 2).to_string(), "2");
    }

    #[derive(Display)]
    enum GenericEnum<A, B> {
        #[display("Gen::A {}", field)]
        A { field: A },
        #[display("Gen::B {}", _0)]
        B(B),
    }
    #[test]
    fn generic_enum() {
        assert_eq!(GenericEnum::A::<_, u8> { field: 1 }.to_string(), "Gen::A 1");
        assert_eq!(GenericEnum::B::<u8, _>(2).to_string(), "Gen::B 2");
    }

    #[derive(Display)]
    enum InterpolatedGenericEnum<A, B> {
        #[display("Gen::A {field}")]
        A { field: A },
        #[display("Gen::B {_0}")]
        B(B),
    }
    #[test]
    fn interpolated_generic_enum() {
        assert_eq!(
            InterpolatedGenericEnum::A::<_, u8> { field: 1 }.to_string(),
            "Gen::A 1",
        );
        assert_eq!(
            InterpolatedGenericEnum::B::<u8, _>(2).to_string(),
            "Gen::B 2",
        );
    }

    #[derive(Display)]
    enum AutoGenericEnum<A, B> {
        A { field: A },
        B(B),
    }
    #[test]
    fn auto_generic_enum() {
        assert_eq!(AutoGenericEnum::A::<_, u8> { field: 1 }.to_string(), "1");
        assert_eq!(AutoGenericEnum::B::<u8, _>(2).to_string(), "2");
    }

    #[derive(Display)]
    #[display("{} {} <-> {0:o} {1:#x} <-> {0:?} {1:X?}", a, b)]
    struct MultiTraitNamedGenericStruct<A, B> {
        a: A,
        b: B,
    }
    #[test]
    fn multi_trait_named_generic_struct() {
        let s = MultiTraitNamedGenericStruct { a: 8u8, b: 255 };
        assert_eq!(s.to_string(), "8 255 <-> 10 0xff <-> 8 FF");
    }

    #[derive(Display)]
    #[display("{} {b} <-> {0:o} {1:#x} <-> {0:?} {1:X?}", a, b)]
    struct InterpolatedMultiTraitNamedGenericStruct<A, B> {
        a: A,
        b: B,
    }
    #[test]
    fn interpolated_multi_trait_named_generic_struct() {
        let s = InterpolatedMultiTraitNamedGenericStruct { a: 8u8, b: 255 };
        assert_eq!(s.to_string(), "8 255 <-> 10 0xff <-> 8 FF");
    }

    #[derive(Display)]
    #[display("{} {} {{}} {0:o} {1:#x} - {0:>4?} {1:^4X?}", _0, _1)]
    struct MultiTraitUnnamedGenericStruct<A, B>(A, B);
    #[test]
    fn multi_trait_unnamed_generic_struct() {
        let s = MultiTraitUnnamedGenericStruct(8u8, 255);
        assert_eq!(s.to_string(), "8 255 {} 10 0xff -    8  FF ");
    }

    #[derive(Display)]
    #[display("{} {_1} {{}} {0:o} {1:#x} - {0:>4?} {1:^4X?}", _0, _1)]
    struct InterpolatedMultiTraitUnnamedGenericStruct<A, B>(A, B);
    #[test]
    fn interpolated_multi_trait_unnamed_generic_struct() {
        let s = InterpolatedMultiTraitUnnamedGenericStruct(8u8, 255);
        assert_eq!(s.to_string(), "8 255 {} 10 0xff -    8  FF ");
    }

    #[derive(Display)]
    #[display("{}", 3 * 4)]
    struct UnusedGenericStruct<T>(T);
    #[test]
    fn unused_generic_struct() {
        let s = UnusedGenericStruct(());
        assert_eq!(s.to_string(), "12");
    }

    mod associated_type_field_enumerator {
        use super::*;

        trait Trait {
            type Type;
        }

        struct Struct;

        impl Trait for Struct {
            type Type = i32;
        }

        #[test]
        fn auto_generic_named_struct_associated() {
            #[derive(Display)]
            struct AutoGenericNamedStructAssociated<T: Trait> {
                field: <T as Trait>::Type,
            }

            let s = AutoGenericNamedStructAssociated::<Struct> { field: 10 };
            assert_eq!(s.to_string(), "10");
        }

        #[test]
        fn auto_generic_unnamed_struct_associated() {
            #[derive(Display)]
            struct AutoGenericUnnamedStructAssociated<T: Trait>(<T as Trait>::Type);

            let s = AutoGenericUnnamedStructAssociated::<Struct>(10);
            assert_eq!(s.to_string(), "10");
        }

        #[test]
        fn auto_generic_enum_associated() {
            #[derive(Display)]
            enum AutoGenericEnumAssociated<T: Trait> {
                Enumerator(<T as Trait>::Type),
            }

            let e = AutoGenericEnumAssociated::<Struct>::Enumerator(10);
            assert_eq!(e.to_string(), "10");
        }
    }

    mod complex_type_field_enumerator {
        use super::*;

        #[derive(Display)]
        struct Struct<T>(T);

        #[test]
        fn auto_generic_named_struct_complex() {
            #[derive(Display)]
            struct AutoGenericNamedStructComplex<T> {
                field: Struct<T>,
            }

            let s = AutoGenericNamedStructComplex { field: Struct(10) };
            assert_eq!(s.to_string(), "10");
        }

        #[test]
        fn auto_generic_unnamed_struct_complex() {
            #[derive(Display)]
            struct AutoGenericUnnamedStructComplex<T>(Struct<T>);

            let s = AutoGenericUnnamedStructComplex(Struct(10));
            assert_eq!(s.to_string(), "10");
        }

        #[test]
        fn auto_generic_enum_complex() {
            #[derive(Display)]
            enum AutoGenericEnumComplex<T> {
                Enumerator(Struct<T>),
            }

            let e = AutoGenericEnumComplex::Enumerator(Struct(10));
            assert_eq!(e.to_string(), "10")
        }
    }

    mod reference {
        use super::*;

        #[test]
        fn auto_generic_reference() {
            #[derive(Display)]
            struct AutoGenericReference<'a, T>(&'a T);

            let s = AutoGenericReference(&10);
            assert_eq!(s.to_string(), "10");
        }

        #[test]
        fn auto_generic_static_reference() {
            #[derive(Display)]
            struct AutoGenericStaticReference<T: 'static>(&'static T);

            let s = AutoGenericStaticReference(&10);
            assert_eq!(s.to_string(), "10");
        }
    }

    mod indirect {
        use super::*;

        #[derive(Display)]
        struct Struct<T>(T);

        #[test]
        fn auto_generic_indirect() {
            #[derive(Display)]
            struct AutoGenericIndirect<T: 'static>(Struct<&'static T>);

            const V: i32 = 10;
            let s = AutoGenericIndirect(Struct(&V));
            assert_eq!(s.to_string(), "10");
        }
    }

    mod raw {
        use super::*;

        #[derive(Display)]
        struct StructOne<T> {
            r#thing: T,
        }

        #[derive(Display)]
        struct StructOneKeyword<T> {
            r#struct: T,
        }

        #[derive(Display)]
        enum Enum<T> {
            One { r#thing: T },
        }

        #[test]
        fn assert() {
            assert_eq!(StructOne::<u8> { r#thing: 8 }.to_string(), "8");
            assert_eq!(StructOneKeyword::<u8> { r#struct: 8 }.to_string(), "8");
            assert_eq!(Enum::<u8>::One { r#thing: 8 }.to_string(), "8");
        }

        mod interpolated {
            use super::*;

            #[derive(Display)]
            #[display("{thing}")]
            struct StructOne<T> {
                r#thing: T,
            }

            #[derive(Display)]
            #[display("{struct}")]
            struct StructOneKeyword<T> {
                r#struct: T,
            }

            #[derive(Display)]
            enum Enum1<T> {
                #[display("{thing}")]
                One { r#thing: T },
            }

            #[derive(Display)]
            enum Enum1Keyword<T> {
                #[display("{struct}")]
                One { r#struct: T },
            }

            #[derive(Display)]
            #[display("{thing}")]
            enum Enum1Top<T> {
                One { r#thing: T },
            }

            #[derive(Display)]
            #[display("{struct}")]
            enum Enum1TopKeyword<T> {
                One { r#struct: T },
            }

            #[derive(Display)]
            #[display("{a}:{b}")]
            struct StructTwo<A, B> {
                r#a: A,
                b: B,
            }

            #[derive(Display)]
            #[display("{pub}:{b}")]
            struct StructTwoKeyword<A, B> {
                r#pub: A,
                b: B,
            }

            #[derive(Display)]
            enum Enum2<A, B> {
                #[display("{a}:{b}")]
                Two { r#a: A, b: B },
            }

            #[derive(Display)]
            enum Enum2Keyword<A, B> {
                #[display("{pub}:{b}")]
                Two { r#pub: A, b: B },
            }

            #[derive(Display)]
            #[display("{a}:{b}")]
            enum Enum2Shared<A, B> {
                Two { r#a: A, b: B },
            }

            #[derive(Display)]
            #[display("{pub}:{b}")]
            enum Enum2SharedKeyword<A, B> {
                Two { r#pub: A, b: B },
            }

            #[test]
            fn assert() {
                assert_eq!(StructOne::<u8> { r#thing: 8 }.to_string(), "8");
                assert_eq!(StructOneKeyword::<u8> { r#struct: 8 }.to_string(), "8");
                assert_eq!(Enum1::<u8>::One { r#thing: 8 }.to_string(), "8");
                assert_eq!(Enum1Keyword::<u8>::One { r#struct: 8 }.to_string(), "8");
                assert_eq!(Enum1Top::<u8>::One { r#thing: 8 }.to_string(), "8");
                assert_eq!(Enum1TopKeyword::<u8>::One { r#struct: 8 }.to_string(), "8");
                assert_eq!(StructTwo::<u8, u16> { r#a: 8, b: 16 }.to_string(), "8:16");
                assert_eq!(
                    StructTwoKeyword::<u8, u16> { r#pub: 8, b: 16 }.to_string(),
                    "8:16",
                );
                assert_eq!(Enum2::<u8, u16>::Two { r#a: 8, b: 16 }.to_string(), "8:16");
                assert_eq!(
                    Enum2Keyword::<u8, u16>::Two { r#pub: 8, b: 16 }.to_string(),
                    "8:16",
                );
                assert_eq!(
                    Enum2Shared::<u8, u16>::Two { r#a: 8, b: 16 }.to_string(),
                    "8:16",
                );
                assert_eq!(
                    Enum2SharedKeyword::<u8, u16>::Two { r#pub: 8, b: 16 }.to_string(),
                    "8:16",
                );
            }
        }
    }

    mod bound {
        use super::*;

        #[test]
        fn simple() {
            #[derive(Display)]
            #[display("{} {}", _0, _1)]
            struct Struct<T1, T2>(T1, T2);

            let s = Struct(10, 20);
            assert_eq!(s.to_string(), "10 20");
        }

        #[test]
        fn debug() {
            #[derive(Debug)]
            struct OnlyDebug;

            #[derive(Display)]
            #[display("{:?}", _0)]
            struct Struct<T>(T);

            let s = Struct(OnlyDebug);
            assert_eq!(s.to_string(), "OnlyDebug");
        }

        #[test]
        fn underscored_simple() {
            #[derive(Display)]
            #[display("{_0} {_1}")]
            struct Struct<T1, T2>(T1, T2);

            let s = Struct(10, 20);
            assert_eq!(s.to_string(), "10 20");
        }

        #[test]
        fn underscored_debug() {
            #[derive(Debug)]
            struct OnlyDebug;

            #[derive(Display)]
            #[display("{_0:?}")]
            struct Struct<T>(T);

            let s = Struct(OnlyDebug);
            assert_eq!(s.to_string(), "OnlyDebug");
        }

        #[test]
        fn redundant() {
            #[derive(Display)]
            #[display(bound(T1: ::core::fmt::Display, T2: ::core::fmt::Debug))]
            #[display("{} {:?}", _0, _1)]
            struct Struct<T1, T2>(T1, T2);

            let s = Struct(10, 20);
            assert_eq!(s.to_string(), "10 20");
        }

        #[test]
        fn underscored_redundant() {
            #[derive(Display)]
            #[display(bound(T1: ::core::fmt::Display, T2: ::core::fmt::Debug))]
            #[display("{_0} {_1:?}")]
            struct Struct<T1, T2>(T1, T2);

            let s = Struct(10, 20);
            assert_eq!(s.to_string(), "10 20");
        }

        #[test]
        fn complex() {
            #[derive(Debug)]
            struct DebugOnly;

            trait Trait1 {
                fn function1(&self) -> &'static str;
            }

            trait Trait2 {
                fn function2(&self) -> &'static str;
            }

            impl Trait1 for i32 {
                fn function1(&self) -> &'static str {
                    "WHAT"
                }
            }

            impl Trait2 for i32 {
                fn function2(&self) -> &'static str {
                    "EVER"
                }
            }

            impl Trait1 for DebugOnly {
                fn function1(&self) -> &'static str {
                    "MAN"
                }
            }

            #[derive(Display)]
            #[display("{} {} {} {} {:?}", _0.function1(), _0, _0.function2(), _1.function1(), _1)]
            #[display(bound(T1: Trait1 + Trait2, T2: Trait1))]
            struct Struct<T1, T2>(T1, T2);

            let s = Struct(10, DebugOnly);
            assert_eq!(s.to_string(), "WHAT 10 EVER MAN DebugOnly");
        }

        #[test]
        fn underscored_complex() {
            #[derive(Debug)]
            struct DebugOnly;

            trait Trait1 {
                fn function1(&self) -> &'static str;
            }

            trait Trait2 {
                fn function2(&self) -> &'static str;
            }

            impl Trait1 for i32 {
                fn function1(&self) -> &'static str {
                    "WHAT"
                }
            }

            impl Trait2 for i32 {
                fn function2(&self) -> &'static str {
                    "EVER"
                }
            }

            impl Trait1 for DebugOnly {
                fn function1(&self) -> &'static str {
                    "MAN"
                }
            }

            #[derive(Display)]
            #[display(bound(T1: Trait1 + Trait2, T2: Trait1))]
            #[display("{} {_0} {} {} {_1:?}", _0.function1(), _0.function2(), _1.function1())]
            struct Struct<T1, T2>(T1, T2);

            let s = Struct(10, DebugOnly);
            assert_eq!(s.to_string(), "WHAT 10 EVER MAN DebugOnly");
        }

        #[test]
        fn explicit_only() {
            trait Trait {
                fn function(&self) -> &'static str;
            }

            struct NoDisplay;

            impl Trait for NoDisplay {
                fn function(&self) -> &'static str {
                    "no display"
                }
            }

            #[derive(Display)]
            #[display("{}", _0.function())]
            #[display(bound(T: Trait))]
            struct Struct<T>(T);

            let s = Struct(NoDisplay);
            assert_eq!(s.to_string(), "no display");
        }
    }

    mod transparency {
        use super::*;

        mod direct {
            use super::*;

            #[derive(
                Display, Binary, Octal, LowerHex, UpperHex, LowerExp, UpperExp, Pointer
            )]
            struct Tuple<T>(T);

            #[derive(
                Display, Binary, Octal, LowerHex, UpperHex, LowerExp, UpperExp, Pointer
            )]
            struct Struct<T> {
                field: T,
            }

            #[derive(
                Display, Binary, Octal, LowerHex, UpperHex, LowerExp, UpperExp, Pointer
            )]
            enum Enum<A, B> {
                A(A),
                B { field: B },
            }

            #[test]
            fn assert() {
                assert_eq!(format!("{:03}", Tuple(7)), "007");
                assert_eq!(format!("{:03}", Struct { field: 7 }), "007");
                assert_eq!(format!("{:03}", Enum::<_, i8>::A(7)), "007");
                assert_eq!(format!("{:03}", Enum::<i8, _>::B { field: 8 }), "008");
                assert_eq!(format!("{:07b}", Tuple(7)), "0000111");
                assert_eq!(format!("{:07b}", Struct { field: 7 }), "0000111");
                assert_eq!(format!("{:07b}", Enum::<_, i8>::A(7)), "0000111");
                assert_eq!(format!("{:07b}", Enum::<i8, _>::B { field: 8 }), "0001000");
                assert_eq!(format!("{:03o}", Tuple(9)), "011");
                assert_eq!(format!("{:03o}", Struct { field: 9 }), "011");
                assert_eq!(format!("{:03o}", Enum::<_, i8>::A(9)), "011");
                assert_eq!(format!("{:03o}", Enum::<i8, _>::B { field: 10 }), "012");
                assert_eq!(format!("{:03x}", Tuple(42)), "02a");
                assert_eq!(format!("{:03x}", Struct { field: 42 }), "02a");
                assert_eq!(format!("{:03x}", Enum::<_, i8>::A(42)), "02a");
                assert_eq!(format!("{:03x}", Enum::<i8, _>::B { field: 43 }), "02b");
                assert_eq!(format!("{:03X}", Tuple(42)), "02A");
                assert_eq!(format!("{:03X}", Struct { field: 42 }), "02A");
                assert_eq!(format!("{:03X}", Enum::<_, i8>::A(42)), "02A");
                assert_eq!(format!("{:03X}", Enum::<i8, _>::B { field: 43 }), "02B");
                assert_eq!(format!("{:07e}", Tuple(42.0)), "004.2e1");
                assert_eq!(format!("{:07e}", Struct { field: 42.0 }), "004.2e1");
                assert_eq!(format!("{:07e}", Enum::<_, i8>::A(42.0)), "004.2e1");
                assert_eq!(
                    format!("{:07e}", Enum::<i8, _>::B { field: 43.0 }),
                    "004.3e1",
                );
                assert_eq!(format!("{:07E}", Tuple(42.0)), "004.2E1");
                assert_eq!(format!("{:07E}", Struct { field: 42.0 }), "004.2E1");
                assert_eq!(format!("{:07E}", Enum::<_, i8>::A(42.0)), "004.2E1");
                assert_eq!(
                    format!("{:07E}", Enum::<i8, _>::B { field: 43.0 }),
                    "004.3E1",
                );
                let (a, b) = (42, 7);
                assert_eq!(format!("{:018p}", Tuple(&a)), format!("{:018p}", &a));
                assert_eq!(
                    format!("{:018p}", Struct { field: &a }),
                    format!("{:018p}", &a),
                );
                assert_eq!(
                    format!("{:018p}", Enum::<_, &i8>::A(&b)),
                    format!("{:018p}", &b),
                );
                assert_eq!(
                    format!("{:018p}", Enum::<&i8, _>::B { field: &a }),
                    format!("{:018p}", &a),
                );
            }
        }

        mod interpolated {
            use super::*;

            #[derive(Display)]
            #[display("{_0}")]
            struct TupleDisplay<T>(T);

            #[derive(Display)]
            #[display("{0:?}", _0)]
            struct TupleDebug<T>(T);

            #[derive(Display)]
            #[display("{_0:b}")]
            struct TupleBinary<T, Y>(T, Y);

            #[derive(Display)]
            #[display("{_1:o}")]
            struct TupleOctal<Y, T>(Y, T);

            #[derive(Display)]
            #[display("{0:x}", _0)]
            struct TupleLowerHex<T>(T);

            #[derive(Display)]
            #[display("{_0:X}")]
            struct TupleUpperHex<T>(T);

            #[derive(Display)]
            #[display("{:e}", _0)]
            struct TupleLowerExp<T>(T);

            #[derive(Display)]
            #[display("{:E}", _0)]
            struct TupleUpperExp<T>(T);

            #[derive(Display)]
            #[display("{_0:p}")]
            struct TuplePointer<T>(T);

            #[derive(Display)]
            #[display("{field}")]
            struct StructDisplay<T> {
                field: T,
            }

            #[derive(Display)]
            #[display("{a:b}")]
            struct StructBinary<T, Y> {
                a: T,
                b: Y,
            }

            #[derive(Display)]
            #[display("{named:o}", named = b)]
            struct StructOctal<Y, T> {
                a: Y,
                b: T,
            }

            #[derive(Display)]
            #[display("{field:x}")]
            struct StructLowerHex<T> {
                field: T,
            }

            #[derive(Display)]
            #[display("{field:X}")]
            struct StructUpperHex<T> {
                field: T,
            }

            #[derive(Display)]
            #[display("{:e}", field)]
            struct StructLowerExp<T> {
                field: T,
            }

            #[derive(Display)]
            #[display("{:E}", field)]
            struct StructUpperExp<T> {
                field: T,
            }

            #[derive(Display)]
            #[display("{field:p}")]
            struct StructPointer<T> {
                field: T,
            }

            #[derive(Display)]
            enum EnumDisplay<A, B> {
                #[display("{_0}")]
                A(A),
                #[display("{}", field)]
                B { field: B },
            }

            #[derive(Display)]
            enum EnumBinary<A, B, C, D> {
                #[display("{_0:b}")]
                A(A, C),
                #[display("{:b}", b)]
                B { b: B, d: D },
            }

            #[derive(Display)]
            enum EnumOctal<A, B, C, D> {
                #[display("{_1:o}")]
                A(A, C),
                #[display("{:o}", d)]
                B { b: B, d: D },
            }

            #[derive(Display)]
            enum EnumLowerHex<A, B> {
                #[display("{_0:x}")]
                A(A),
                #[display("{:x}", field)]
                B { field: B },
            }

            #[derive(Display)]
            enum EnumUpperHex<A, B> {
                #[display("{_0:X}")]
                A(A),
                #[display("{:X}", field)]
                B { field: B },
            }

            #[derive(Display)]
            enum EnumLowerExp<A, B> {
                #[display("{:e}", _0)]
                A(A),
                #[display("{field:e}")]
                B { field: B },
            }

            #[derive(Display)]
            enum EnumUpperExp<A, B> {
                #[display("{:E}", _0)]
                A(A),
                #[display("{field:E}")]
                B { field: B },
            }

            #[derive(Display)]
            enum EnumPointer<A, B> {
                #[display("{_0:p}")]
                A(A),
                #[display("{field:p}")]
                B { field: B },
            }

            #[test]
            fn assert() {
                assert_eq!(format!("{:03}", TupleDisplay(7)), "007");
                assert_eq!(format!("{:03}", TupleDebug(8)), "008");
                assert_eq!(format!("{:03}", StructDisplay { field: 7 }), "007");
                assert_eq!(format!("{:03}", EnumDisplay::<_, i8>::A(7)), "007");
                assert_eq!(
                    format!("{:03}", EnumDisplay::<i8, _>::B { field: 8 }),
                    "008",
                );
                assert_eq!(format!("{:07}", TupleBinary(7, ())), "0000111");
                assert_eq!(format!("{:07}", StructBinary { a: 7, b: () }), "0000111");
                assert_eq!(
                    format!("{:07}", EnumBinary::<_, i8, _, ()>::A(7, ())),
                    "0000111",
                );
                assert_eq!(
                    format!("{:07}", EnumBinary::<i8, _, (), _>::B { b: 8, d: () }),
                    "0001000",
                );
                assert_eq!(format!("{:03}", TupleOctal((), 9)), "011");
                assert_eq!(format!("{:03}", StructOctal { a: (), b: 9 }), "011");
                assert_eq!(
                    format!("{:03}", EnumOctal::<_, (), _, i8>::A((), 9)),
                    "011",
                );
                assert_eq!(
                    format!("{:03}", EnumOctal::<(), _, i8, _>::B { b: (), d: 10 }),
                    "012",
                );
                assert_eq!(format!("{:03}", TupleLowerHex(42)), "02a");
                assert_eq!(format!("{:03}", StructLowerHex { field: 42 }), "02a");
                assert_eq!(format!("{:03}", EnumLowerHex::<_, i8>::A(42)), "02a");
                assert_eq!(
                    format!("{:03}", EnumLowerHex::<i8, _>::B { field: 43 }),
                    "02b",
                );
                assert_eq!(format!("{:03}", TupleUpperHex(42)), "02A");
                assert_eq!(format!("{:03}", StructUpperHex { field: 42 }), "02A");
                assert_eq!(format!("{:03}", EnumUpperHex::<_, i8>::A(42)), "02A");
                assert_eq!(
                    format!("{:03}", EnumUpperHex::<i8, _>::B { field: 43 }),
                    "02B",
                );
                assert_eq!(format!("{:07}", TupleLowerExp(42.0)), "004.2e1");
                assert_eq!(format!("{:07}", StructLowerExp { field: 42.0 }), "004.2e1");
                assert_eq!(format!("{:07}", EnumLowerExp::<_, i8>::A(42.0)), "004.2e1");
                assert_eq!(
                    format!("{:07}", EnumLowerExp::<i8, _>::B { field: 43.0 }),
                    "004.3e1",
                );
                assert_eq!(format!("{:07}", TupleUpperExp(42.0)), "004.2E1");
                assert_eq!(format!("{:07}", StructUpperExp { field: 42.0 }), "004.2E1");
                assert_eq!(format!("{:07}", EnumUpperExp::<_, i8>::A(42.0)), "004.2E1");
                assert_eq!(
                    format!("{:07}", EnumUpperExp::<i8, _>::B { field: 43.0 }),
                    "004.3E1",
                );
                let (a, b) = (42, 7);
                assert_eq!(format!("{:018}", TuplePointer(&a)), format!("{:018p}", &a));
                assert_eq!(
                    format!("{:018}", StructPointer { field: &a }),
                    format!("{:018p}", &a),
                );
                assert_eq!(
                    format!("{:018}", EnumPointer::<_, &i8>::A(&b)),
                    format!("{:018p}", &b),
                );
                assert_eq!(
                    format!("{:018}", EnumPointer::<&i8, _>::B { field: &a }),
                    format!("{:018p}", &a),
                );
            }

            mod shared_format {
                use super::*;

                #[derive(Display)]
                #[display("{_0}")]
                enum EnumDisplay<A, B> {
                    A(A),
                    B(B),
                }

                #[derive(Display)]
                #[display("{:b}", _0)]
                enum EnumBinary<A, B, C, D> {
                    A(A, C),
                    B(B, D),
                }

                #[derive(Display)]
                #[display("{:o}", d)]
                enum EnumOctal<A, B, C, D> {
                    A { b: A, d: C },
                    B { b: B, d: D },
                }

                #[derive(Display)]
                #[display("{field:x}")]
                enum EnumLowerHex<A, B> {
                    A { field: A },
                    B { field: B },
                }

                #[derive(Display)]
                #[display("{:X}", field)]
                enum EnumUpperHex<A, B> {
                    A { field: A },
                    B { field: B },
                }

                #[derive(Display)]
                #[display("{_0:e}")]
                enum EnumLowerExp<A, B> {
                    A(A),
                    B(B),
                }

                #[derive(Display)]
                #[display("{:E}", _0)]
                enum EnumUpperExp<A, B> {
                    A(A),
                    B(B),
                }

                #[derive(Display)]
                #[display("{_0:p}")]
                enum EnumPointer<A, B> {
                    A(A),
                    B(B),
                }

                #[test]
                fn assert() {
                    assert_eq!(format!("{:03}", EnumDisplay::<i8, u8>::A(7)), "007");
                    assert_eq!(format!("{:03}", EnumDisplay::<i8, u8>::B(8)), "008");
                    assert_eq!(format!("{:07}", TupleBinary(7, ())), "0000111");
                    assert_eq!(
                        format!("{:07}", EnumBinary::<i8, u8, (), ()>::A(7, ())),
                        "0000111",
                    );
                    assert_eq!(
                        format!("{:07}", EnumBinary::<i8, u8, (), ()>::B(8, ())),
                        "0001000",
                    );
                    assert_eq!(
                        format!(
                            "{:03}",
                            EnumOctal::<(), (), i8, u8>::A { b: (), d: 9 },
                        ),
                        "011",
                    );
                    assert_eq!(
                        format!(
                            "{:03}",
                            EnumOctal::<(), (), i8, u8>::B { b: (), d: 10 },
                        ),
                        "012",
                    );
                    assert_eq!(
                        format!("{:03}", EnumLowerHex::<i8, u8>::A { field: 42 }),
                        "02a",
                    );
                    assert_eq!(
                        format!("{:03}", EnumLowerHex::<i8, u8>::B { field: 43 }),
                        "02b",
                    );
                    assert_eq!(
                        format!("{:03}", EnumUpperHex::<i8, u8>::A { field: 42 }),
                        "02A",
                    );
                    assert_eq!(
                        format!("{:03}", EnumUpperHex::<i8, u8>::B { field: 43 }),
                        "02B",
                    );
                    assert_eq!(
                        format!("{:07}", EnumLowerExp::<f32, f64>::A(42.0)),
                        "004.2e1"
                    );
                    assert_eq!(
                        format!("{:07}", EnumLowerExp::<f32, f64>::B(43.0)),
                        "004.3e1"
                    );
                    assert_eq!(
                        format!("{:07}", EnumUpperExp::<f32, f64>::A(42.0)),
                        "004.2E1"
                    );
                    assert_eq!(
                        format!("{:07}", EnumUpperExp::<f32, f64>::B(43.0)),
                        "004.3E1",
                    );
                    let (a, b) = (42, 7);
                    assert_eq!(
                        format!("{:018}", EnumPointer::<&i8, &u8>::A(&b)),
                        format!("{:018p}", &b),
                    );
                    assert_eq!(
                        format!("{:018}", EnumPointer::<&i8, &u8>::B(&a)),
                        format!("{:018p}", &a),
                    );
                }

                mod mixed {
                    use super::*;

                    #[derive(Display)]
                    #[display("{_variant}")]
                    enum EnumDisplay<A, B> {
                        A(A),
                        #[display("{_0}")]
                        B(B),
                    }

                    #[derive(Display)]
                    #[display("{_variant}")]
                    enum EnumBinary<A, B, C, D> {
                        #[display("{_0:b}")]
                        A(A, C),
                        #[display("{:b}", b)]
                        B { b: B, d: D },
                    }

                    #[derive(Display)]
                    #[display("{_variant}")]
                    enum EnumOctal<A, B, C, D> {
                        #[display("{_1:o}")]
                        A(A, C),
                        #[display("{:o}", d)]
                        B { b: B, d: D },
                    }

                    #[derive(Display)]
                    #[display("{_variant}")]
                    enum EnumLowerHex<A, B> {
                        #[display("{_0:x}")]
                        A(A),
                        #[display("{:x}", field)]
                        B { field: B },
                    }

                    #[derive(Display)]
                    #[display("{_variant}")]
                    enum EnumUpperHex<A, B> {
                        #[display("{_0:X}")]
                        A(A),
                        #[display("{:X}", field)]
                        B { field: B },
                    }

                    #[derive(Display)]
                    #[display("{_variant}")]
                    enum EnumLowerExp<A, B> {
                        #[display("{:e}", _0)]
                        A(A),
                        #[display("{field:e}")]
                        B { field: B },
                    }

                    #[derive(Display)]
                    #[display("{_variant}")]
                    enum EnumUpperExp<A, B> {
                        #[display("{:E}", _0)]
                        A(A),
                        #[display("{field:E}")]
                        B { field: B },
                    }

                    #[derive(Display)]
                    #[display("{_variant}")]
                    enum EnumPointer<A, B> {
                        #[display("{_0:p}")]
                        A(A),
                        #[display("{field:p}")]
                        B { field: B },
                    }

                    #[test]
                    fn assert() {
                        assert_eq!(
                            format!("{:03}", EnumDisplay::<i8, u8>::A(7)),
                            "007",
                        );
                        assert_eq!(
                            format!("{:03}", EnumDisplay::<i8, u8>::B(8)),
                            "008",
                        );
                        assert_eq!(
                            format!("{:07}", EnumBinary::<_, i8, _, ()>::A(7, ())),
                            "0000111",
                        );
                        assert_eq!(
                            format!(
                                "{:07}",
                                EnumBinary::<i8, _, (), _>::B { b: 8, d: () },
                            ),
                            "0001000",
                        );
                        assert_eq!(
                            format!("{:03}", EnumOctal::<_, (), _, i8>::A((), 9)),
                            "011",
                        );
                        assert_eq!(
                            format!(
                                "{:03}",
                                EnumOctal::<(), _, i8, _>::B { b: (), d: 10 }
                            ),
                            "012",
                        );
                        assert_eq!(
                            format!("{:03}", EnumLowerHex::<_, i8>::A(42)),
                            "02a",
                        );
                        assert_eq!(
                            format!("{:03}", EnumLowerHex::<i8, _>::B { field: 43 }),
                            "02b",
                        );
                        assert_eq!(
                            format!("{:03}", EnumUpperHex::<_, i8>::A(42)),
                            "02A",
                        );
                        assert_eq!(
                            format!("{:03}", EnumUpperHex::<i8, _>::B { field: 43 }),
                            "02B",
                        );
                        assert_eq!(
                            format!("{:07}", EnumLowerExp::<_, i8>::A(42.0)),
                            "004.2e1",
                        );
                        assert_eq!(
                            format!("{:07}", EnumLowerExp::<i8, _>::B { field: 43.0 }),
                            "004.3e1",
                        );
                        assert_eq!(
                            format!("{:07}", EnumUpperExp::<_, i8>::A(42.0)),
                            "004.2E1",
                        );
                        assert_eq!(
                            format!("{:07}", EnumUpperExp::<i8, _>::B { field: 43.0 }),
                            "004.3E1",
                        );
                        let (a, b) = (42, 7);
                        assert_eq!(
                            format!("{:018}", EnumPointer::<_, &i8>::A(&b)),
                            format!("{:018p}", &b),
                        );
                        assert_eq!(
                            format!("{:018}", EnumPointer::<&i8, _>::B { field: &a }),
                            format!("{:018p}", &a),
                        );
                    }
                }
            }
        }

        mod omitted {
            use super::*;

            mod on_modifiers {
                use super::*;

                #[derive(Display)]
                enum Enum<A, B, C, D> {
                    #[display("{_0:x?}")]
                    LowerDebug(A),
                    #[display("{_0:X?}")]
                    UpperDebug(B),
                    #[display("{:^}", _0)]
                    Align(C),
                    #[display("{:+}", _0)]
                    Sign(C),
                    #[display("{:#b}", _0)]
                    Alternate(C),
                    #[display("{:0}", _0)]
                    ZeroPadded(C),
                    #[display("{:07}", _0)]
                    Width(C),
                    #[display("{:.5}", _0)]
                    Precision(D),
                }

                #[test]
                fn assert() {
                    assert_eq!(
                        format!("{:03}", Enum::<_, u8, u8, f64>::LowerDebug(7)),
                        "7",
                    );
                    assert_eq!(
                        format!("{:03}", Enum::<u8, _, u8, f64>::UpperDebug(8)),
                        "8",
                    );
                    assert_eq!(format!("{:03}", Enum::<u8, u8, _, f64>::Align(5)), "5");
                    assert_eq!(format!("{:03}", Enum::<u8, u8, _, f64>::Sign(5)), "+5");
                    assert_eq!(
                        format!("{:07}", Enum::<u8, u8, _, f64>::Alternate(5)),
                        "0b101",
                    );
                    assert_eq!(
                        format!("{:07}", Enum::<u8, u8, _, f64>::ZeroPadded(-5)),
                        "-5",
                    );
                    assert_eq!(
                        format!("{:03}", Enum::<u8, u8, _, f64>::Width(5)),
                        "0000005",
                    );
                    assert_eq!(
                        format!("{:.3}", Enum::<u8, u8, u8, _>::Precision(1.23456789)),
                        "1.23457",
                    );
                }
            }
        }
    }

    mod r#unsized {
        use core::ptr;

        use super::*;

        #[derive(Display)]
        struct Tuple<T: ?Sized>(T);

        #[derive(Display)]
        struct Struct<T: ?Sized> {
            tail: T,
        }

        #[test]
        fn assert() {
            let dat = "14";

            let t =
                unsafe { &*(ptr::addr_of!(*dat) as *const [i32] as *const Tuple<str>) };
            assert_eq!(t.to_string(), "14");
            let s = unsafe {
                &*(ptr::addr_of!(*dat) as *const [i32] as *const Struct<str>)
            };
            assert_eq!(s.to_string(), "14");
        }

        mod interpolated {
            use core::ptr;

            use super::*;

            #[derive(Display)]
            #[display("{}.", _0)]
            struct Tuple1<T: ?Sized>(T);

            #[derive(Display)]
            #[display("{_0}.")]
            struct Tuple2<T: ?Sized>(T);

            #[derive(Display)]
            #[display("{}.", tail)]
            struct Struct1<T: ?Sized> {
                tail: T,
            }

            #[derive(Display)]
            #[display("{tail}.")]
            struct Struct2<T: ?Sized> {
                tail: T,
            }

            #[test]
            fn assert() {
                let dat = "14";

                let t1 = unsafe {
                    &*(ptr::addr_of!(*dat) as *const [i32] as *const Tuple1<str>)
                };
                assert_eq!(t1.to_string(), "14.");
                let t2 = unsafe {
                    &*(ptr::addr_of!(*dat) as *const [i32] as *const Tuple2<str>)
                };
                assert_eq!(t2.to_string(), "14.");
                let s1 = unsafe {
                    &*(ptr::addr_of!(*dat) as *const [i32] as *const Struct1<str>)
                };
                assert_eq!(s1.to_string(), "14.");
                let s2 = unsafe {
                    &*(ptr::addr_of!(*dat) as *const [i32] as *const Struct2<str>)
                };
                assert_eq!(s2.to_string(), "14.");
            }
        }
    }
}

// See: https://github.com/JelteF/derive_more/issues/363
mod type_variables {
    mod our_alloc {
        #[cfg(not(feature = "std"))]
        pub use alloc::{boxed::Box, format, vec::Vec};
        #[cfg(not(feature = "std"))]
        pub use core::iter;
        #[cfg(feature = "std")]
        pub use std::{boxed::Box, format, iter, vec::Vec};
    }

    use our_alloc::{format, iter, Box};

    // We want `Vec` in scope to test that code generation works if it is there.
    #[allow(unused_imports)]
    use our_alloc::Vec;

    use derive_more::with_trait::Display;

    #[derive(Display, Debug)]
    #[display("{inner:?}")]
    #[display(bounds(T: Display))]
    struct OptionalBox<T> {
        inner: Option<Box<T>>,
    }

    #[derive(Display, Debug)]
    #[display("{next}")]
    struct ItemStruct {
        next: OptionalBox<ItemStruct>,
    }

    #[derive(Display)]
    #[derive(Debug)]
    struct ItemTuple(OptionalBox<ItemTuple>);

    #[derive(Display)]
    #[derive(Debug)]
    #[display("Item({_0})")]
    struct ItemTupleContainerFmt(OptionalBox<ItemTupleContainerFmt>);

    #[derive(Display, Debug)]
    #[display("{next}")]
    enum ItemEnumOuterFormat {
        Variant1 {
            next: OptionalBox<ItemEnumOuterFormat>,
        },
        Variant2 {
            next: OptionalBox<i32>,
        },
    }

    #[derive(Display, Debug)]
    enum ItemEnumInnerFormat {
        #[display("{next} {inner}")]
        Node {
            next: OptionalBox<ItemEnumInnerFormat>,
            inner: i32,
        },
        #[display("{inner}")]
        Leaf { inner: i32 },
    }

    #[derive(Display)]
    #[derive(Debug)]
    #[display("{next:?}, {real:?}")]
    struct VecMeansDifferent<Vec> {
        next: our_alloc::Vec<i32>,
        real: Vec,
    }

    #[derive(Display)]
    #[derive(Debug)]
    #[display("{t:?}")]
    struct Array<T> {
        t: [T; 10],
    }

    mod parens {
        #![allow(unused_parens)] // test that type is found even in parentheses

        use derive_more::Display;

        #[derive(Display)]
        struct Paren<T> {
            t: (T),
        }
    }

    #[derive(Display)]
    struct ParenthesizedGenericArgumentsInput<T> {
        t: dyn Fn(T) -> i32,
    }

    #[derive(Display)]
    struct ParenthesizedGenericArgumentsOutput<T> {
        t: dyn Fn(i32) -> T,
    }

    #[derive(Display)]
    struct Ptr<T> {
        t: *const T,
    }

    #[derive(Display)]
    struct Reference<'a, T> {
        t: &'a T,
    }

    #[derive(Display)]
    struct Slice<'a, T> {
        t: &'a [T],
    }

    #[derive(Display)]
    struct BareFn<T> {
        t: Box<fn(T) -> T>,
    }

    #[derive(Display)]
    struct Tuple<T> {
        t: Box<(T, T)>,
    }

    trait MyTrait<T> {}

    #[derive(Display)]
    struct TraitObject<T> {
        t: Box<dyn MyTrait<T>>,
    }

    #[derive(Display)]
    #[display("{iter:?} with {elem:?}")]
    struct AssocType<I: Iterator> {
        iter: I,
        elem: Option<I::Item>,
    }

    #[derive(Display)]
    #[display("{item:?} with {elem:?}")]
    struct CollidedPathName<Item> {
        item: Item,
        elem: Option<some_path::Item>,
    }

    mod some_path {
        #[derive(Debug)]
        pub struct Item;
    }

    #[test]
    fn assert() {
        assert_eq!(
            format!(
                "{}",
                ItemStruct {
                    next: OptionalBox {
                        inner: Some(Box::new(ItemStruct {
                            next: OptionalBox { inner: None },
                        })),
                    },
                },
            ),
            "Some(ItemStruct { next: OptionalBox { inner: None } })",
        );

        assert_eq!(
            format!(
                "{}",
                ItemTuple(OptionalBox {
                    inner: Some(Box::new(ItemTuple(OptionalBox { inner: None }))),
                }),
            ),
            "Some(ItemTuple(OptionalBox { inner: None }))",
        );

        assert_eq!(
            format!(
                "{}",
                ItemTupleContainerFmt(OptionalBox {
                    inner: Some(Box::new(ItemTupleContainerFmt(OptionalBox {
                        inner: None,
                    }))),
                }),
            ),
            "Item(Some(ItemTupleContainerFmt(OptionalBox { inner: None })))",
        );

        let item = ItemEnumOuterFormat::Variant1 {
            next: OptionalBox {
                inner: Some(Box::new(ItemEnumOuterFormat::Variant2 {
                    next: OptionalBox { inner: None },
                })),
            },
        };
        assert_eq!(
            format!("{item}"),
            "Some(Variant2 { next: OptionalBox { inner: None } })",
        );

        assert_eq!(
            format!(
                "{}",
                AssocType {
                    iter: iter::empty::<bool>(),
                    elem: None,
                },
            ),
            "Empty with None",
        );

        assert_eq!(
            format!(
                "{}",
                CollidedPathName {
                    item: false,
                    elem: Some(some_path::Item),
                },
            ),
            "false with Some(Item)",
        );
    }
}
