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
136
137
138
139
140
141
142
143
144
use std::{fs, ops::Deref, path::Path};

use dlopen2::wrapper::{Container, WrapperApi};

use crate::{
    types::{HotloadInner, MAX_LOAD_INDEX, UA},
    R,
};

pub struct EventNewDll<API: WrapperApi> {
    action: bool,
    inner: UA<HotloadInner<API>>,
    swith_value: Option<(usize, Container<API>)>,
}

impl<API: WrapperApi + 'static> Deref for EventNewDll<API> {
    type Target = Container<API>;
    fn deref(&self) -> &Self::Target {
        self.swith_value
            .as_ref()
            .map(|x| &x.1)
            .expect("New dll not loaded")
    }
}

impl<API: WrapperApi> EventNewDll<API> {
    pub(crate) fn new(call: UA<HotloadInner<API>>) -> R<Self> {
        let swith_value = Self::load_new(call.clone())?;
        let drop = Self {
            action: true,
            inner: call,
            swith_value: Some(swith_value),
        };
        Ok(drop)
    }

    // 取消本次加载
    pub fn cancel(&mut self) {
        self.action = false;
        debug!("Cancel load new dll");
    }

    pub(crate) fn load_new(_self: UA<HotloadInner<API>>) -> R<(usize, Container<API>)> {
        let inner = _self.get_mut();
        let mut load_index = inner.load_index + 1;
        if load_index >= MAX_LOAD_INDEX {
            load_index = 0;
        }

        // 加载新的
        // 获得文件名. 重命名, 在名称中加入后缀 ".下标" 重命名;
        let f_name = crate::types::get_file_name(&inner.path)?;
        let f_old: &Path = std::path::Path::new(&inner.path);
        let mut f_new = f_old.to_path_buf();
        let new_name = format!(".{}_hotload_{f_name}", load_index);
        f_new.set_file_name(new_name);
        fs::copy(f_old, f_new.clone())?;

        let c: Container<API> = unsafe { Container::load(&f_new) }?;
        debug!("load new dll start: {load_index}");
        // inner.container[load_index] = Some(c);
        // // 添加索引即生效
        // inner.load_index = load_index;
        // debug!("load new container: {load_index}");

        Ok((load_index, c))
    }

    fn swith(&mut self) {
        if !self.action {
            return;
        }
        let inner = self.inner.get_mut();
        if let Some((load_index, c)) = self.swith_value.take() {
            inner.container[load_index] = Some(c);

            // 添加索引即生效
            inner.load_index = load_index;
            debug!("load new dll: {load_index} complete!");
        }
    }
}



impl<API: WrapperApi> Drop for EventNewDll<API> {
    fn drop(&mut self) {
        self.swith();
    }
}

pub struct EventOldDll<API: WrapperApi> {
    action: bool,
    inner: UA<HotloadInner<API>>,
    cur_index: usize,
}

impl<API: WrapperApi + 'static> Deref for EventOldDll<API> {
    type Target = Container<API>;
    fn deref(&self) -> &Self::Target {
        let inner = &*self.inner;
        let inner = &inner.container[self.cur_index];
        inner.as_ref().expect("Old dll not loaded")
    }
}

impl<API: WrapperApi> EventOldDll<API> {
    pub fn new(call: UA<HotloadInner<API>>) -> Self {
        let cur_index = call.get_mut().load_index;
        let drop = Self {
            action: true,
            inner: call,
            cur_index,
        };
        drop
    }

    // 取消本次加载
    pub fn cancel(&mut self) {
        self.action = false;
        debug!("Cancel release old dll");
    }

    fn release_old(&self) {
        if !self.action {
            return;
        }
        let inner = self.inner.get_mut();
        let load_index = self.cur_index;

        let take_v = inner.container[load_index].take();
        if let Some(api) = take_v {
            debug!("release old dll {load_index} start, please wait");
            drop(api);
            debug!("release old dll {load_index} complete!");
        }
    }
}

impl<API: WrapperApi> Drop for EventOldDll<API> {
    fn drop(&mut self) {
        self.release_old()
    }
}