// So I was working on Nullable,
// and I thought: how could this be made to work better?
// The following code runs on DMD master,
// and it is, technically, `safe`;
// but it REALLY REALLY shouldn't be.
module turducken;

import std.algorithm;
import std.datetime;

// The Turducken Type Technique is the answer to a challenge.
// How do we perform late binding and early unbinding
// on a type that's really, really evil?

// First of all, let's set the stage.
// We're going to construct the Type from Hell.
// It's a struct value type, giving us the
// greatest number of avenues to be horrible.
struct Satan
{
// It has an immutable value field, referencing immutable data.
    immutable int[] i;

    // It has a SysTime: it's caused issues for
    // me in the past and I hold a grudge.
    SysTime st;

    // It has no default constructor.
    @disable this();

    // It has an .init that violates its invariant.
    bool properlyInitialized = false;

    invariant { assert(properlyInitialized); }

    // It has a copy assignment overload,
    // specifically so we can forbid copy assignment.
    void opAssign(Satan) { assert(false); }

// To confirm that every constructor call matches one destructor call,
    // it counts references.
    int *refs;

    this(int* refs)
    pure @safe @nogc
    {
        this.properlyInitialized = true;
        this.refs = refs;
        (*refs)++;
    }

    this(this)
    pure @safe @nogc
    { (*refs)++; }

    // Since a destructor is defined, we will definitely
    // assert out if the .init value is ever destructed.
    ~this()
    pure @safe @nogc
    in(refs)
    out(; *refs >= 0)
    do { (*refs)--; }
}

// Now, this is the challenge.

// In a function that is
pure // pure,
@safe // safe,
@nogc // and nogc:
unittest
{
// perform late binding and early unbinding of the Type from Hell.

    // Let's do some prep.

    // (for validation)
    int refs;

    // (cheat a bit)
    int* refsp = () @trusted { return &refs; }();

    {
        // We start with a default initialized variable.
        Turducken!Satan magic;

        // we bind it to a constructed value
        magic.bind(Satan(refsp));

        // There's now exactly one copy of Satan in the world:
        assert(refs == 1);

        // Just for laughs, bind over it:
        magic.bind(Satan(refsp));

        // Still only one copy around.
        assert(refs == 1);

        // all is well with the contained value
        assert(magic.value.properlyInitialized);

        // Now we unbind it before scope end
        magic.unbind;

        // Satan is gone now.
        assert(refs == 0);
    }
    // And he was destroyed exactly once, as is proper.
    assert(refs == 0);
}

// How did we do this?
// Turducken!
struct Turducken(T)
{
    // The delicious center.
    alias Chicken = T;

    // Union ensures that the T destructor is not called.
    union Duck
    {
        Chicken chicken; // chicken chicken? chicken!
    }

    // Struct ensures that moveEmplace and its magic
    // constness "tolerant" (violating) memcpy can be used.
    struct Turkey
    {
        Duck duck;
    }

    Turkey store = Turkey.init; // take you to the turkey store

    bool set = false;

    // Stick a straw in it to get at the delicious gooey center.
    @property ref T value() in(set) { return store.duck.chicken; }

    // And the special sauce:
    void bind(T value)
    {
        // clean up in case we're back for seconds
        unbind;

        // Make a destructor-protected copy to stick in our store
        Turkey wrapper = Turkey(Duck(value));

// Plow over the existing data in total disregard of constness
        () @trusted { moveEmplace(wrapper, store); }();

        set = true;
    }

    // Various condiments:
    void unbind()
    {
        if (set)
        {
            static if (is(T == struct)) {
                destroy(value);
            }
            set = false;
        }
    }

    // Since we have shielded our value from D's watchful eyes,
    // we have to remember to clean up manually
    // Clean your dishes!
    ~this()
    {
        unbind;
    }
}

// And that's the Turducken Type Technique. Deliciously evil!

Reply via email to