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
use gc::{
    Finalize,
    Trace,
    GcCell,
    Gc,
};
use proc_macro2::{
    TokenStream,
    Ident,
};
use quote::ToTokens;
use crate::{
    util::{
        LateInit,
    },
    node::node::{
        Node,
        RedirectRef,
        NodeMethods,
        ToDep,
    },
    derive_forward_node_methods,
    schema::GenerateContext,
    scope::Scope,
};

use super::node::Node_;

#[derive(Trace, Finalize)]
pub(crate) struct NodeCustomMut_ {
    pub(crate) serial: Vec<LateInit<RedirectRef<Node, Node>>>,
    pub(crate) rust: Option<Node>,
}

#[derive(Trace, Finalize)]
pub(crate) struct NodeCustom_ {
    pub(crate) scope: Scope,
    pub(crate) id: String,
    #[unsafe_ignore_trace]
    pub(crate) id_ident: Ident,
    #[unsafe_ignore_trace]
    pub(crate) rust_type: TokenStream,
    #[unsafe_ignore_trace]
    pub(crate) read_code: Box<dyn Fn(&Vec<Ident>, &TokenStream) -> TokenStream>,
    #[unsafe_ignore_trace]
    pub(crate) write_code: Box<dyn Fn(&TokenStream, &Vec<Ident>) -> TokenStream>,
    pub(crate) mut_: GcCell<NodeCustomMut_>,
}

impl NodeMethods for NodeCustom_ {
    fn gather_read_deps(&self) -> Vec<Node> {
        return self.mut_.borrow().serial.dep();
    }

    fn generate_read(&self, _gen_ctx: &GenerateContext) -> TokenStream {
        let dest_ident = &self.id_ident;
        let mut source_idents = vec![];
        for serial in &self.mut_.borrow().serial {
            source_idents.push(serial.as_ref().unwrap().primary.id_ident());
        }
        return (self.read_code)(&source_idents, &dest_ident.into_token_stream());
    }

    fn gather_write_deps(&self) -> Vec<Node> {
        return self.mut_.borrow().rust.dep();
    }

    fn generate_write(&self, _gen_ctx: &GenerateContext) -> TokenStream {
        let mut dest_idents = vec![];
        for serial in &self.mut_.borrow().serial {
            dest_idents.push(serial.as_ref().unwrap().primary.id_ident());
        }
        return (self.write_code)(&self.id_ident.clone().into_token_stream(), &dest_idents);
    }

    fn set_rust(&self, rust: Node) {
        let mut mut_ = self.mut_.borrow_mut();
        if let Some(r) = &mut_.rust {
            if r.id() != rust.id() {
                panic!("Rust end of {} already connected to node {}", self.id, r.id());
            }
        }
        mut_.rust = Some(rust);
    }

    fn scope(&self) -> Scope {
        return self.scope.clone();
    }

    fn id(&self) -> String {
        return self.id.clone();
    }

    fn id_ident(&self) -> Ident {
        return self.id_ident.clone();
    }

    fn rust_type(&self) -> TokenStream {
        return self.rust_type.clone();
    }
}

#[derive(Clone, Trace, Finalize)]
pub struct NodeCustom(pub(crate) Gc<NodeCustom_>);

impl Into<Node> for NodeCustom {
    fn into(self) -> Node {
        return Node(Node_::Custom(self));
    }
}

derive_forward_node_methods!(NodeCustom);