1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
use std::any::TypeId;

use common::protocol::tag::MockTagVisitor;
use effectful::{blocking::BlockingSpin, Effective as _};
use treaty::{
    any::{OwnedStatic, WithLtTypeId},
    protocol::{
        visitor::{Tag, TagConst, TagDyn, Value, VisitResult},
        DynVisitor,
    },
    symbol::Symbol,
    walk::DynWalkerAdapter,
    Flow,
};

use crate::common::{builder::MockBuilder, walker::MockWalker};

mod common;

/// Tests that the tag protocol can be visited with a value walker.
#[test]
fn tag_can_be_visited() {
    let mut mock = MockTagVisitor::<TagDyn, BlockingSpin>::new();

    // Expect a visit with the tag protocol.
    mock.expect_visit()
        .once()
        .returning(|TagDyn(kind), walker| {
            // The kind should be test.
            assert_eq!(kind, Symbol::new("test"));

            let mut builder = MockBuilder::<(), (), (), BlockingSpin>::new();

            // Expect that the builder is attempted to be used by the walker for the value.
            builder.expect_traits_mut().once().return_const(None);

            // Walk the value of the tag.
            assert_eq!(
                walker.walk(DynVisitor(&mut builder)).wait(),
                Flow::Done
            );

            // We are done.
            VisitResult::Control(Flow::Done)
        });

    // Use the tag protocol trait.
    let visitor: &mut dyn Tag<TagDyn, BlockingSpin> = &mut mock;

    let mut walker = MockWalker::<(), (), BlockingSpin>::new();

    // Expect the tag value to be walked.
    walker.expect_walk().once().returning(|visitor| {
        // Attempt to use the visitor.
        assert!(visitor
            .upcast::<dyn Value<OwnedStatic<i32>, BlockingSpin>>()
            .is_none());

        Ok(())
    });

    // We need to use the adapter to make the walker object safe to pass to the protocol.
    let mut walker = DynWalkerAdapter::new(walker);

    // Visit the tag protocol for kind test with the value walker.
    assert!(matches!(
        visitor
            .visit(TagDyn(Symbol::new("test")), &mut walker)
            .wait(),
        VisitResult::Control(Flow::Done)
    ));
}

/// Checks that compile time tag symbols work.
#[test]
fn const_tag_can_be_visited() {
    const TEST: u64 = Symbol::new("test").to_int();

    let mut mock = MockTagVisitor::<TagConst<TEST>, BlockingSpin>::new();

    // Expect a visit with the tag protocol.
    mock.expect_visit().once().returning(|TagConst, walker| {
        let mut builder = MockBuilder::<(), (), (), BlockingSpin>::new();

        // Expect that the builder is attempted to be used by the walker for the value.
        builder.expect_traits_mut().once().return_const(None);

        // Walk the value of the tag.
        assert_eq!(
            walker.walk(DynVisitor(&mut builder)).wait(),
            Flow::Done
        );

        // We are done.
        VisitResult::Control(Flow::Done)
    });

    // Use the tag protocol trait.
    let visitor: &mut dyn Tag<TagConst<TEST>, BlockingSpin> = &mut mock;

    let mut walker = MockWalker::<(), (), BlockingSpin>::new();

    // Expect the tag value to be walked.
    walker.expect_walk().once().returning(|visitor| {
        // Attempt to use the visitor.
        assert!(visitor
            .upcast::<dyn Value<OwnedStatic<i32>, BlockingSpin>>()
            .is_none());

        Ok(())
    });

    // We need to use the adapter to make the walker object safe to pass to the protocol.
    let mut walker = DynWalkerAdapter::new(walker);

    // Visit the tag protocol for kind test with the value walker.
    assert!(matches!(
        visitor.visit(TagConst, &mut walker).wait(),
        VisitResult::Control(Flow::Done)
    ));
}

#[test]
fn tag_proto() {
    // The type id of the higher ranked type.
    let id = TypeId::of::<dyn Tag<TagDyn, BlockingSpin>>();

    // The type id for the lifetime containing value protocol trait object.
    let name_id = WithLtTypeId::of::<dyn Tag<TagDyn, BlockingSpin>>();

    // // They should be the same.
    // assert_eq!(id, name_id.into_type_id());
}
*/