<!-- @dd-navbar -->
<!-- this line automatically maintained by update-navbars --><nav style="text-align: right; margin-bottom: 12px;">[ <em>docs: <a href="https://docs.rs/derive-deftly/latest/derive_deftly/index.html">crate top-level</a> | <a href="https://docs.rs/derive-deftly/latest/derive_deftly/index.html#overall-toc">overall toc, macros</a> | <a href="https://docs.rs/derive-deftly/latest/derive_deftly/doc_reference/index.html">template etc. reference</a> | <a href="https://diziet.pages.torproject.net/rust-derive-deftly/latest/guide/"><strong>guide/tutorial</strong></a></em> ]</nav>

# A brute-force approach for applying to structs and enums

One way we can solve [our problems](./difference-problems.md)
with writing a `derive_deftly(Diff)` template
is a brute-force approach.
Here we just use [conditionals](constructor-conditionals.md)
to write different versions of our template
for the `struct` case and the `enum` case.
To handle the difference between tuple and unit structs and variants,
we can use conditionals as well.

Here are the new conditions we'll need:
  * [`is_enum`][c:is_enum] - True if the top-level type is an enum.
  * [`is_struct`][c:is_struct] - True if the top-level type is a struct.
  * [`v_is_unit`][c:v_is_unit] - True if the current variant
    (or the top-level type, in the case of a struct)
    is a unit struct/variant.
  * [`v_is_tuple`][c:v_is_tuple] - True if the current variant
    (or the top-level type, in the case of a struct)
    is a tuple struct/variant.
  * [`v_is_named`][c:v_is_named] - True if the current variant
    (or the top-level type, in the case of a struct)
    is a struct/variant with named fields.

With these conditions, we can write our template,
albeit with quite a lot of redundancy.

> Note 1: You may want to refresh your memory about
> [`${select1}`](constructor-conditionals.md#select1)
> and [`$<pasting>`](paste-and-case.md).
>
> Note 2: We're ignoring generics in this example, for clarity.

<!-- TODO: When I use $crate:: below, the rustdoc doesn't pass its tests. -->
<!-- We should investigate. -->

```rust
# pub trait Diff { type Difference: std::fmt::Debug; }
# impl Diff for u32 { type Difference = (); }
# use derive_deftly::{define_derive_deftly, Deftly};
define_derive_deftly!{
    Diff:

    ${define DIFF_TYPE
        { Option< <$ftype as Diff>:: Difference> }
    }

    ${select1 is_struct {
        ${select1 v_is_unit {
            #[derive(Debug)]
            $tvis struct $<$tname Diff>;
        } else if v_is_tuple {
            #[derive(Debug)]
            $tvis struct $<$tname Diff>(
                ${for fields {$DIFF_TYPE , }}
            );
        } else if v_is_named {
            #[derive(Debug)]
            $tvis struct $<$tname Diff> {
                $(
                    $fvis $fname: $DIFF_TYPE,
                )
            }
        }} // end select1
    } else if is_enum {
        #[derive(Debug)]
        $tvis enum $<$tname Diff> {
            $(
                ${select1 v_is_unit {
                    // nothing to do; we don't emit anything here.
                } else if v_is_tuple {
                    $<Both $vname>(
                        ${for fields {$DIFF_TYPE , }}
                    ),
                } else if v_is_named {
                    $<Both $vname> {
                        $(
                            $fname: $DIFF_TYPE,
                        )
                    },
                }} // end select1
            ) // end iteration over variants

            VariantChanged {
                original_value: $ttype,
                new_value: $ttype,
            },
        }
    }} // end select1
    impl Diff for $tname {
        type Difference = $<$tname Diff>;

        // ... and at this point, you still have to define
        // an implementation for `fn diff()`: good luck!
    }
}
# use derive_deftly_template_Diff;
# #[derive(Clone,Debug,Deftly)]
# #[derive_deftly(Diff)]
# struct Unit;
# #[derive(Clone,Debug,Deftly)]
# #[derive_deftly(Diff)]
# struct Tuple(u32, u32);
# #[derive(Clone,Debug,Deftly)]
# #[derive_deftly(Diff)]
# struct Named { a: u32, b: u32 }
# #[derive(Clone,Debug,Deftly)]
# #[derive_deftly(Diff)]
# enum Enum { Un, Tup(u32,u32), Nam { a: u32, b: u32 } }
```

This is a viable approach, but not a very maintanable one:
look how we've had to copy out our definition separately
for every possible Rust syntax!
We managed to save some repetition with `$define`,
but we can still do better.

<!-- TODO: I'd rather not have to use $for above; see #110. -->


[c:is_enum]: https://docs.rs/derive-deftly/latest/derive_deftly/doc_reference/index.html#c:is_enum
[c:is_struct]: https://docs.rs/derive-deftly/latest/derive_deftly/doc_reference/index.html#c:is_struct
[c:v_is_unit]: https://docs.rs/derive-deftly/latest/derive_deftly/doc_reference/index.html#c:v_is_unit
[c:v_is_tuple]: https://docs.rs/derive-deftly/latest/derive_deftly/doc_reference/index.html#c:v_is_tuple
[c:v_is_named]: https://docs.rs/derive-deftly/latest/derive_deftly/doc_reference/index.html#c:v_is_named
