hexroll3_scroll/
instance.rs1use std::cell::RefCell;
26use std::collections::HashMap;
27use std::path::PathBuf; use anyhow::anyhow;
30use anyhow::Result;
31use minijinja::Environment;
32use rand::distributions::Alphanumeric;
33use rand::rngs::ThreadRng;
34use rand::seq::SliceRandom;
35use rand::thread_rng;
36use rand::Rng;
37
38use crate::generators::roll;
39use crate::parser::parse_buffer;
40use crate::parser::parse_file;
41use crate::renderer_env::prepare_renderer;
42use crate::repository::*;
43use crate::semantics::*;
44
45pub struct SandboxBuilder<'a> {
48 pub sandbox: &'a SandboxInstance,
49 pub randomizer: Randomizer,
50 pub templating_env: Environment<'a>,
51}
52
53impl<'a> SandboxBuilder<'a> {
54 pub fn from_instance(instance: &'a SandboxInstance) -> Self {
55 let mut env = Environment::new();
56 prepare_renderer(&mut env, instance);
57 SandboxBuilder {
58 sandbox: instance,
59 randomizer: Randomizer::new(),
60 templating_env: env,
61 }
62 }
63}
64
65pub struct SandboxInstance {
68 pub sid: Option<String>,
69 pub classes: HashMap<String, Class>,
70 pub repo: Repository,
71 pub globals: HashMap<String, serde_json::Value>,
72}
73
74impl SandboxInstance {
75 pub fn new() -> Self {
76 SandboxInstance {
77 sid: None,
78 classes: HashMap::new(),
79 repo: Repository::new(),
80 globals: HashMap::new(),
81 }
82 }
83
84 pub fn with_scroll(&mut self, scroll_filepath: PathBuf) -> Result<&mut Self> {
85 parse_file(self, scroll_filepath)?;
86 Ok(self)
87 }
88
89 pub fn open(&mut self, filepath: &str) -> Result<&mut Self> {
90 self.repo.open(filepath)?;
91 let root = self.repo.inspect(|tx| tx.load("root"))?;
92 if let Some(sid) = root.value.as_str() {
93 self.sid = Some(sid.to_string());
94 Ok(self)
95 } else {
96 Err(anyhow!("Unable to find root entity in {}", filepath))
97 }
98 }
99
100 pub fn create(&mut self, filepath: &str) -> Result<&mut Self> {
101 self.repo.create(filepath)?;
102
103 if let Ok(sid) = self.repo.mutate(|tx| {
104 let builder = SandboxBuilder::from_instance(self);
105 let ret = roll(&builder, tx, "main", "root", None);
106 tx.store("root", &serde_json::json!(ret.as_ref().unwrap()))?;
107 ret
108 }) {
109 self.sid = Some(sid.to_string());
110 Ok(self)
111 } else {
112 Err(anyhow!(
113 "Was unable to create a new sandbox in {}",
114 filepath
115 ))
116 }
117 }
118
119 pub fn sid(&self) -> Option<String> {
120 self.sid.clone()
121 }
122
123 pub fn parse_buffer(&mut self, buffer: &str) -> &mut Self {
124 parse_buffer(self, buffer, None, None).unwrap();
125 self
126 }
127}
128
129impl Default for SandboxInstance {
130 fn default() -> Self {
131 Self::new()
132 }
133}
134
135pub struct Randomizer {
136 rng: RefCell<ThreadRng>, }
138
139impl Randomizer {
140 pub fn new() -> Self {
141 Randomizer {
142 rng: RefCell::new(thread_rng()),
143 }
144 }
145
146 pub fn choose<'a, T>(&self, v: &'a Vec<T>) -> &'a T {
147 match v.choose(&mut *self.rng.borrow_mut()) {
148 Some(item) => item,
149 None => panic!("List is empty"),
150 }
151 }
152
153 pub fn uid(&self) -> String {
154 let mut rng = self.rng.borrow_mut();
155 (0..8).map(|_| rng.sample(Alphanumeric) as char).collect()
156 }
157
158 pub fn in_range(&self, min: i32, max: i32) -> i32 {
159 let mut rng = self.rng.borrow_mut();
160 rng.gen_range(min..max + 1)
161 }
162}
163
164impl Default for Randomizer {
165 fn default() -> Self {
166 Self::new()
167 }
168}