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
use crate::{Ident, MakeImpl, Module, Path, RuntimeType, Type, WipFunction, WipImpl};
use std::cell::RefCell;
use std::rc::Rc;
use std::thread::LocalKey;

thread_local!(pub(crate) static WIP: Rc<RefCell<Option<WipFunction>>> = Rc::new(RefCell::new(None)));

#[derive(Clone, Copy)]
pub struct Execution<'a> {
    pub(crate) ty: &'a Type,
    pub(crate) tracker: &'a Tracker,
}

#[derive(Debug, Clone)]
pub(crate) struct Tracker {
    pub(crate) crates: RefCell<Vec<Ident>>,
    pub(crate) impls: RefCell<Vec<WipImpl>>,
}

impl<'a> Execution<'a> {
    pub fn load_crate(self, name: &str) -> Module {
        self.tracker.load_crate(name)
    }

    pub fn make_trait_impl<TraitType, SelfType>(
        self,
        trait_type: TraitType,
        self_type: SelfType,
        run: fn(MakeImpl),
    ) where
        TraitType: RuntimeType,
        SelfType: RuntimeType,
    {
        self.tracker
            .make_trait_impl(trait_type.SELF(), self_type.SELF(), run);
    }

    pub fn target_type(self) -> Type {
        self.ty.clone()
    }
}

impl Tracker {
    pub(crate) fn new() -> Self {
        Tracker {
            crates: RefCell::new(Vec::new()),
            impls: RefCell::new(Vec::new()),
        }
    }

    fn load_crate(&self, name: &str) -> Module {
        self.crates.borrow_mut().push(Ident::new(name));
        Module {
            path: Path::empty().get_path(name),
        }
    }

    fn make_trait_impl(&self, trait_ty: Type, ty: Type, run: fn(MakeImpl)) {
        let wip = WipImpl {
            trait_ty: Some(trait_ty),
            ty,
            functions: RefCell::new(Vec::new()),
        };
        run(MakeImpl { wip: &wip });
        self.impls.borrow_mut().push(wip);
    }
}

pub(crate) trait StaticBorrow<T> {
    fn with_borrow<R, F>(&'static self, f: F) -> R
    where
        F: FnOnce(&T) -> R;
    fn with_borrow_mut<R, F>(&'static self, f: F) -> R
    where
        F: FnOnce(&mut T) -> R;
}

impl<T> StaticBorrow<T> for LocalKey<Rc<RefCell<Option<T>>>> {
    // These functions will panic if self is None or in cases where
    // RefCell::borrow and RefCell::borrow_mut would normally panic
    fn with_borrow<R, F>(&'static self, f: F) -> R
    where
        F: FnOnce(&T) -> R,
    {
        self.with(|opt| f(opt.borrow().as_ref().unwrap()))
    }

    fn with_borrow_mut<R, F>(&'static self, f: F) -> R
    where
        F: FnOnce(&mut T) -> R,
    {
        self.with(|opt| f(opt.borrow_mut().as_mut().unwrap()))
    }
}