grass_runtime/
const_bag.rs

1use std::{cell::UnsafeCell, str::FromStr};
2
3use lazy_static::lazy_static;
4
5//TODO
6
7lazy_static! {
8    static ref RAW_VALUES: Vec<String> = {
9        let mut ret = Vec::new();
10        let const_bag = std::env::var("__GRASS_CONST_BAG")
11            .unwrap_or_else(|_| panic!("Unable to read environment variable __GRASS_CONST_BAG"));
12        let mut buf = String::new();
13        let mut escape = false;
14        for c in const_bag.chars() {
15            if escape == false {
16                if c == '\\' {
17                    escape = true;
18                } else if c == ';' {
19                    ret.push(std::mem::take(&mut buf));
20                } else {
21                    buf.push(c);
22                }
23            } else {
24                if c == ';' {
25                    buf.push(';');
26                } else if c == '\\' {
27                    buf.push('\\');
28                } else {
29                    panic!("Invalid constant bag: {}", const_bag);
30                }
31                escape = false;
32            }
33        }
34        if escape {
35            panic!("Invalid constant bag: {}", const_bag);
36        }
37        ret.push(buf);
38        ret
39    };
40}
41
42pub enum ConstBagRefImpl<T> {
43    BagRef(usize),
44    Value(T),
45}
46
47pub struct ConstBagRef<T> {
48    inner: UnsafeCell<ConstBagRefImpl<T>>,
49}
50
51pub trait ConstBagType {
52    type ReadOutput;
53    fn value(self) -> Self::ReadOutput;
54}
55
56impl<'a> ConstBagType for &'a ConstBagRef<f64> {
57    type ReadOutput = f64;
58    fn value(self) -> f64 {
59        *self.get_ref()
60    }
61}
62
63impl<'a> ConstBagType for &'a ConstBagRef<String> {
64    type ReadOutput = &'a str;
65    fn value(self) -> &'a str {
66        self.get_ref().as_str()
67    }
68}
69
70impl<T> ConstBagRef<T> {
71    pub const fn new(size: usize) -> ConstBagRef<T> {
72        ConstBagRef {
73            inner: UnsafeCell::new(ConstBagRefImpl::BagRef(size)),
74        }
75    }
76    pub fn get_ref(&self) -> &T
77    where
78        T: FromStr,
79    {
80        let idx = match unsafe { &*self.inner.get() } {
81            ConstBagRefImpl::Value(value) => return value,
82            ConstBagRefImpl::BagRef(idx) => *idx,
83        };
84        let inner_mut = unsafe { &mut *self.inner.get() };
85
86        let value = match T::from_str(RAW_VALUES.get(idx).unwrap()) {
87            Ok(what) => what,
88            Err(_) => panic!("Unable to parse the value"),
89        };
90
91        *inner_mut = ConstBagRefImpl::Value(value);
92
93        match unsafe { &*self.inner.get() } {
94            ConstBagRefImpl::Value(value) => return value,
95            ConstBagRefImpl::BagRef(_) => unreachable!(),
96        }
97    }
98}