grass_runtime/
const_bag.rs1use std::{cell::UnsafeCell, str::FromStr};
2
3use lazy_static::lazy_static;
4
5lazy_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}