// File: dechimal[P]TaggedUnion/test_product.cpp
// Function: main
int main() {
    {
        // basic
        auto v1 = product<int, int const>{1, 2};
        auto const v2 = v1;
        static_assert(std::is_same<decltype(v1.get(_0)), int &>{}, "failed to basic 1");
        static_assert(std::is_same<decltype(v1.get(_1)), int const &>{}, "failed to basic 2");
        static_assert(std::is_same<decltype(v2.get(_0)), int const &>{}, "failed to basic 3");
        static_assert(std::is_same<decltype(v2.get(_1)), int const &>{}, "failed to basic 4");
        assert(v1.get(_0) == 1);
        assert(v1.get(_1) == 2);
    }
    {
        // with recursion
        struct u {};
        using state = sum<u, int>;
        using stream = product<int, std::function<_()>>;
        auto f = fix([] (auto f, auto st) -> std::function<stream()> {
            return [f, st] {
                return st.when([&] (tag<0>, u) {
                    return stream{0, f(state(_1, 0))};
                }, [&] (tag<1>, int i) {
                    return stream{i + 1, f(state(_1, i + 1))};
                });
            };
        });
        auto s = f(state(_0))();
        assert(s.get(_0) == 0);
        s = s.get(_1)();
        assert(s.get(_0) == 1);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
movl $0x0, -0x4(%rbp)
movl $0x1, -0x10(%rbp)
movl $0x2, -0x14(%rbp)
leaq -0xc(%rbp), %rdi
leaq -0x10(%rbp), %rsi
leaq -0x14(%rbp), %rdx
callq 0x2a60
leaq -0x1c(%rbp), %rdi
leaq -0xc(%rbp), %rsi
callq 0x2a90
leaq -0xc(%rbp), %rdi
callq 0x2ab0
cmpl $0x1, (%rax)
jne 0x11fe
jmp 0x121d
leaq 0x2ed4(%rip), %rdi      # 0x40d9
leaq 0x2edd(%rip), %rsi      # 0x40e9
movl $0x1e, %edx
leaq 0x2ee2(%rip), %rcx      # 0x40fa
callq 0x1070
leaq -0xc(%rbp), %rdi
callq 0x2ae0
cmpl $0x2, (%rax)
jne 0x122d
jmp 0x124c
leaq 0x2ed1(%rip), %rdi      # 0x4105
leaq 0x2eae(%rip), %rsi      # 0x40e9
movl $0x1f, %edx
leaq 0x2eb3(%rip), %rcx      # 0x40fa
callq 0x1070
leaq -0x20(%rbp), %rdi
callq 0x1400
leaq -0x78(%rbp), %rdi
movq %rdi, -0xc8(%rbp)
callq 0x14b0
movq -0xc8(%rbp), %rdx
leaq -0x70(%rbp), %rdi
leaq -0x1f(%rbp), %rsi
callq 0x1420
jmp 0x127b
leaq -0x50(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0x2b10
jmp 0x128a
leaq -0x70(%rbp), %rdi
callq 0x2b60
leaq -0x78(%rbp), %rdi
callq 0x14e0
leaq -0x50(%rbp), %rdi
callq 0x2b80
movq %rax, -0xd0(%rbp)
jmp 0x12ae
movq -0xd0(%rbp), %rax
cmpl $0x0, (%rax)
jne 0x12bc
jmp 0x132f
leaq 0x2e52(%rip), %rdi      # 0x4115
leaq 0x2e1f(%rip), %rsi      # 0x40e9
movl $0x30, %edx
leaq 0x2e24(%rip), %rcx      # 0x40fa
callq 0x1070
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
jmp 0x130a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0x70(%rbp), %rdi
callq 0x2b60
leaq -0x78(%rbp), %rdi
callq 0x14e0
jmp 0x13f1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
jmp 0x13e8
leaq -0x50(%rbp), %rdi
callq 0x2bb0
movq %rax, -0xd8(%rbp)
jmp 0x1341
movq -0xd8(%rbp), %rsi
leaq -0xb8(%rbp), %rdi
callq 0x2b10
jmp 0x1356
leaq -0x50(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0x2be0
jmp 0x1368
leaq -0xb8(%rbp), %rdi
callq 0x2c20
leaq -0x50(%rbp), %rdi
callq 0x2b80
movq %rax, -0xe0(%rbp)
jmp 0x1386
movq -0xe0(%rbp), %rax
cmpl $0x1, (%rax)
jne 0x1394
jmp 0x13d3
leaq 0x2d89(%rip), %rdi      # 0x4124
leaq 0x2d47(%rip), %rsi      # 0x40e9
movl $0x32, %edx
leaq 0x2d4c(%rip), %rcx      # 0x40fa
callq 0x1070
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x2c20
jmp 0x13e8
leaq -0x50(%rbp), %rdi
callq 0x2c20
movl -0x4(%rbp), %eax
addq $0xe0, %rsp
popq %rbp
retq
leaq -0x50(%rbp), %rdi
callq 0x2c20
movq -0x88(%rbp), %rdi
callq 0x10a0
nopl (%rax)