// File: oknenavin[P]cxon/examples/user-types-ex02.cxx
// Function: main
struct B_union {
        int d1;                     // from D1
        std::string d2;             // from D2
        B_union() : d1(), d2() {}   // define proper defaults as from all the members
                                    // the real type should be decidable
        // tis class is only used for reading
        CXON_JSON_CLS_READ_MEMBER(B_union, CXON_JSON_CLS_FIELD_ASIS(d1), CXON_JSON_CLS_FIELD_ASIS(d2))
    };

    // specialize the read/write structs for B*

    template <typename X>
        struct read<JSON<X>, B*> {
            template <typename II, typename Cx, typename Y = JSON<X>>
                static bool value(B*& t, II& i, II e, Cx& cx) {
                    if (!cio::consume<Y>(i, e, cx)) // consume any white-spaces
                        return false;
                    if (cio::peek(i, e) == *Y::id::nil) // check/read null
                        return read_value<Y>(t, i, e, cx);
                    B_union p; // the union type that represents a B*
                        if (read_value<Y>(p, i, e, cx)) { // try reading it
                            if (p.d1) // let d1 != 0 indicates D1
                                return (t = alc::make_in_context<D1>(cx, p.d1)); // create and assign D1
                            // create and assign D2
                            return (t = alc::make_in_context<D2>(cx, std::move(p.d2)));
                        }
                        return false;
                }
        };

    template <typename X>
        struct write<JSON<X>, B*> {
            template <typename O, typename Cx, typename Y = JSON<X>>
                static bool value(O& o, const B* t, Cx& cx) {
                    if (!t) // check/write null
                            return write_value<Y>(o, nullptr, cx);
                    // cast and write the runtime type
                    switch (t->type) {
                        case B::D1:
                            return write_value<Y>(o, static_cast<const D1*>(t), cx);
                        case B::D2:
                            return write_value<Y>(o, static_cast<const D2*>(t), cx);
                    }
                    return false;
                }
        };

}


int main() {
    U u;
        cxon::from_bytes(u,
            R"({"polymorphic": [{"d2": "42"}, {"d1": 42}]})"
        );
    std::string o;
        cxon::to_bytes(o, u);
    assert(o == R"({"polymorphic":[{"d2":"42"},{"d1":42}]})");
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movl $0x0, -0x4(%rbp)
leaq -0x20(%rbp), %rdi
movq %rdi, -0x88(%rbp)
callq 0x27f0
movq -0x88(%rbp), %rsi
leaq 0x9f74(%rip), %rdx      # 0xc304
leaq -0x38(%rbp), %rdi
callq 0x2810
jmp 0x239b
leaq -0x68(%rbp), %rdi
movq %rdi, -0x90(%rbp)
callq 0x2200
movq -0x90(%rbp), %rsi
leaq -0x80(%rbp), %rdi
leaq -0x20(%rbp), %rdx
callq 0x2840
jmp 0x23c1
leaq 0x9f68(%rip), %rsi      # 0xc330
leaq -0x68(%rbp), %rdi
callq 0x2870
movb %al, -0x91(%rbp)
jmp 0x23d9
movb -0x91(%rbp), %al
testb $0x1, %al
jne 0x23e5
jmp 0x23e7
jmp 0x242b
leaq 0x9f6a(%rip), %rdi      # 0xc358
leaq 0x9f95(%rip), %rsi      # 0xc38a
movl $0x67, %edx
leaq 0x9f9d(%rip), %rcx      # 0xc39e
callq 0x2140
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x2449
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x2120
jmp 0x2449
leaq -0x68(%rbp), %rdi
callq 0x2120
leaq -0x20(%rbp), %rdi
callq 0x28a0
movl -0x4(%rbp), %eax
addq $0xa0, %rsp
popq %rbp
retq
leaq -0x20(%rbp), %rdi
callq 0x28a0
movq -0x40(%rbp), %rdi
callq 0x2230
nopl (%rax,%rax)