1use std::collections::HashSet;
26use std::sync::Arc;
27
28use anyhow::{anyhow, Result};
29
30use crate::frame::*;
31use crate::generators::*;
32use crate::instance::*;
33use crate::renderer::render_entity;
34use crate::repository::*;
35use crate::semantics::*;
36
37pub trait ValueAssigner {
40 fn new(name: String, value: serde_json::Value) -> Self;
41}
42
43pub trait EntityAssigner {
47 fn new(
58 name: String,
59 class_names: ClassNamesToRoll,
60 min: CardinalityValue,
61 max: CardinalityValue,
62 injectors: Injectors,
63 ) -> Self;
64}
65
66pub trait RefInjectCommand {
67 fn make(name: String, path: Vec<String>) -> Arc<dyn InjectCommand + Send + Sync>;
68}
69
70#[derive(Clone)]
71pub enum CardinalityValue {
72 Number(i32),
73 Variable(String),
74 Undefined,
75}
76
77#[derive(Clone)]
78pub enum ClassNamesToRoll {
79 List(Vec<String>),
80 Indirect(String),
81 Unset(),
82}
83
84#[derive(Clone)]
92pub struct AttrCommandAssigner {
93 pub name: String,
94 pub value: serde_json::Value,
95}
96
97impl ValueAssigner for AttrCommandAssigner {
98 fn new(name: String, value: serde_json::Value) -> Self {
99 AttrCommandAssigner { name, value }
100 }
101}
102
103impl AttrCommand for AttrCommandAssigner {
104 fn apply(
105 &self,
106 _ctx: &mut Context,
107 _builder: &SandboxBuilder,
108 tx: &mut ReadWriteTransaction,
109 euid: &str,
110 ) -> Result<()> {
111 let entity = tx.load(euid)?;
112 if entity.as_object().unwrap().contains_key(&self.name) && self.value.is_boolean() {
113 log::warn!(
114 "Entity class {} has an override with value {} for attribute {} already set to {}",
115 entity["class"],
116 self.value,
117 self.name,
118 entity[&self.name]
119 );
120 }
121 entity[&self.name] = self.value.to_owned();
122 Ok(())
123 }
124
125 fn revert(
126 &self,
127 _ctx: &mut Context,
128 _builder: &SandboxBuilder,
129 tx: &mut ReadWriteTransaction,
130 euid: &str,
131 ) -> Result<()> {
132 let entity = tx.load(euid)?;
133 entity.clear(&self.name);
134 Ok(())
135 }
136 fn value(&self) -> Option<String> {
137 Some(self.value.as_str().unwrap().to_string())
138 }
139}
140
141#[derive(Clone)]
153pub struct AttrCommandWeakAssigner {
154 pub name: String,
155 pub value: serde_json::Value,
156}
157
158impl AttrCommand for AttrCommandWeakAssigner {
159 fn apply(
160 &self,
161 _ctx: &mut Context,
162 _builder: &SandboxBuilder,
163 tx: &mut ReadWriteTransaction,
164 euid: &str,
165 ) -> Result<()> {
166 let entity = tx.load(euid)?;
167 entity[&self.name] = serde_json::Value::Null;
168 Ok(())
169 }
170
171 fn revert(
172 &self,
173 _ctx: &mut Context,
174 _builder: &SandboxBuilder,
175 tx: &mut ReadWriteTransaction,
176 euid: &str,
177 ) -> Result<()> {
178 let entity = tx.load(euid)?;
179 entity.clear(&self.name);
180 Ok(())
181 }
182 fn value(&self) -> Option<String> {
183 Some(self.value.as_str().unwrap().to_string())
184 }
185}
186
187#[derive(Clone)]
195pub struct AttrCommandDice {
196 pub name: String,
197 pub number_of_dice: i32,
198 pub dice_type: i32,
199 pub dice_modifier: i32,
200}
201
202impl AttrCommand for AttrCommandDice {
203 fn apply(
204 &self,
205 _ctx: &mut Context,
206 builder: &SandboxBuilder,
207 tx: &mut ReadWriteTransaction,
208 euid: &str,
209 ) -> Result<()> {
210 let mut total: i32 = 0;
211 for _ in 0..self.number_of_dice {
212 total += builder.randomizer.in_range(1, self.dice_type);
213 }
214 total += self.dice_modifier;
215 let entity = tx.load(euid)?;
216 entity[&self.name] = serde_json::to_value(total).unwrap();
217 Ok(())
218 }
219
220 fn revert(
221 &self,
222 _ctx: &mut Context,
223 _builder: &SandboxBuilder,
224 tx: &mut ReadWriteTransaction,
225 euid: &str,
226 ) -> Result<()> {
227 let entity = tx.load(euid)?;
228 entity.clear(&self.name);
229 Ok(())
230 }
231}
232
233#[derive(Clone)]
241pub struct AttrCommandPrerenderedAssigner {
242 pub name: String,
243 pub value: serde_json::Value,
244}
245
246impl AttrCommand for AttrCommandPrerenderedAssigner {
247 fn apply(
248 &self,
249 _ctx: &mut Context,
250 builder: &SandboxBuilder,
251 tx: &mut ReadWriteTransaction,
252 euid: &str,
253 ) -> Result<()> {
254 let ro_entity = tx.retrieve(euid)?;
255 let rendered = render_entity(builder.sandbox, tx, &ro_entity.value, true)?;
256 let prerendered = builder
257 .templating_env
258 .render_str(self.value.as_str().unwrap(), &rendered)?;
259 let entity = tx.load(euid)?;
260 entity[&self.name] = serde_json::Value::String(prerendered);
261 Ok(())
262 }
263
264 fn revert(
265 &self,
266 _ctx: &mut Context,
267 _builder: &SandboxBuilder,
268 tx: &mut ReadWriteTransaction,
269 euid: &str,
270 ) -> Result<()> {
271 let entity = tx.load(euid)?;
272 entity.clear(&self.name);
273 Ok(())
274 }
275 fn value(&self) -> Option<String> {
276 Some(self.value.as_str().unwrap().to_string())
277 }
278}
279
280#[derive(Clone)]
292pub struct AttrCommandRollEntity {
293 pub name: String,
294 pub class_names: ClassNamesToRoll,
295 pub min: CardinalityValue,
296 pub max: CardinalityValue,
297 pub injectors: Injectors,
298}
299
300impl EntityAssigner for AttrCommandRollEntity {
301 fn new(
302 name: String,
303 class_names: ClassNamesToRoll,
304 min: CardinalityValue,
305 max: CardinalityValue,
306 injectors: Injectors,
307 ) -> Self {
308 AttrCommandRollEntity {
309 name,
310 class_names,
311 min,
312 max,
313 injectors,
314 }
315 }
316}
317
318impl AttrCommand for AttrCommandRollEntity {
319 fn apply(
320 &self,
321 ctx: &mut Context,
322 builder: &SandboxBuilder,
323 tx: &mut ReadWriteTransaction,
324 euid: &str,
325 ) -> Result<()> {
326 let (min, max) = match ctx {
327 Context::Appending(_) => (1, 1),
328 Context::Rerolling(_) => (1, 1),
329 Context::Rolling => (
330 resolve_value(builder, &self.min),
331 resolve_value(builder, &self.max),
332 ),
333 _ => return Err(anyhow!("Invalid context when applying roll: {:#?}", ctx)),
334 };
335 let class_names = match &self.class_names {
336 ClassNamesToRoll::List(v) => v.clone(),
337 ClassNamesToRoll::Indirect(s) => {
338 let entity = tx.load(euid)?;
339 vec![entity[s].as_str().unwrap().to_string()]
340 }
341 ClassNamesToRoll::Unset() => unreachable!(),
342 };
343 let uid = {
344 let entity = tx.load(euid)?;
345 entity["uid"].as_str().unwrap().to_string()
346 };
347 let seq =
348 if max == 0 && min == 0 {
349 serde_json::json!([])
350 } else {
351 let n = if max - min > 0 {
352 builder.randomizer.in_range(min, max)
353 } else {
354 min
355 };
356 let mut ret: serde_json::Value = {
357 let entity = tx.load(euid)?;
358 match ctx {
359 Context::Appending(_) => entity[&self.name].clone(),
360 Context::Rerolling(_) => entity[&self.name].clone(),
361 Context::Rolling => serde_json::json!([]),
362 _ => return Err(anyhow!("Invalid context when applying roll: {:#?}", ctx)),
363 }
364 };
365 for _ in 0..n {
366 let actual_class_name = builder.randomizer.choose::<String>(&class_names);
367 let generated_uid =
368 roll(builder, tx, actual_class_name, &uid, Some(&self.injectors))?;
369 {
370 let entity = tx.load(&generated_uid)?;
371 entity["$parent"] = serde_json::json!({
372 "uid": &uid,
373 "attr": self.name,
374 });
375 tx.save(&generated_uid)?;
376 }
377
378 if let Context::Rerolling(payload) = ctx {
379 if let Some(index) = ret.as_array_mut().unwrap().iter().position(|value| {
380 value.as_str().unwrap() == payload.existing_uid.as_str()
381 }) {
382 ret.as_array_mut().unwrap()[index] =
383 serde_json::Value::from(generated_uid.clone());
384 payload.new_uid = Some(generated_uid.clone());
385 } else {
386 }
387 } else {
388 ret.as_array_mut()
389 .unwrap()
390 .push(serde_json::Value::from(generated_uid.clone()));
391 }
392
393 if let Context::Appending(payload) = ctx {
394 payload.appended_uid = Some(generated_uid.clone());
395 }
396 collect(builder, tx, &uid, generated_uid.as_str(), actual_class_name)?;
397 }
398 serde_json::json!(ret)
399 };
400 {
401 let entity = tx.load(euid)?;
402 entity[&self.name] = seq;
403 }
404 Ok(())
405 }
406
407 fn revert(
408 &self,
409 _ctx: &mut Context,
410 builder: &SandboxBuilder,
411 tx: &mut ReadWriteTransaction,
412 euid: &str,
413 ) -> Result<()> {
414 let entity = tx.load(euid)?;
415 if let Some(arr) = entity[&self.name].as_array() {
432 for euid in arr.clone() {
433 unroll(builder, tx, euid.as_str().unwrap(), Some(&self.injectors))?;
434 }
435 }
436 Ok(())
438 }
439}
440
441#[derive(Clone)]
454pub struct AttrCommandRollFromList {
455 pub name: String,
456 pub list: Vec<serde_json::Value>,
457}
458
459impl AttrCommand for AttrCommandRollFromList {
460 fn apply(
461 &self,
462 _ctx: &mut Context,
463 builder: &SandboxBuilder,
464 tx: &mut ReadWriteTransaction,
465 euid: &str,
466 ) -> Result<()> {
467 let entity = tx.load(euid)?;
468 entity[&self.name] = builder.randomizer.choose(&self.list).to_owned();
469 Ok(())
470 }
471
472 fn revert(
473 &self,
474 _ctx: &mut Context,
475 _builder: &SandboxBuilder,
476 tx: &mut ReadWriteTransaction,
477 euid: &str,
478 ) -> Result<()> {
479 let entity = tx.load(euid)?;
480 entity.clear(&self.name);
481 Ok(())
482 }
483}
484
485#[derive(Clone)]
493pub struct AttrCommandContext {
494 pub name: String,
495 pub context_parent: String,
496 pub context_attr: String,
497}
498
499impl AttrCommand for AttrCommandContext {
500 fn apply(
501 &self,
502 _ctx: &mut Context,
503 _builder: &SandboxBuilder,
504 tx: &mut ReadWriteTransaction,
505 euid: &str,
506 ) -> Result<()> {
507 let entity = tx.load(euid)?;
508 entity[&self.name] = serde_json::json!({
509 "type" : "context",
510 "spec" : {
511 "parent" : self.context_parent,
512 "attr" : self.context_attr
513 }
514 });
515 Ok(())
516 }
517
518 fn revert(
519 &self,
520 _ctx: &mut Context,
521 _builder: &SandboxBuilder,
522 tx: &mut ReadWriteTransaction,
523 euid: &str,
524 ) -> Result<()> {
525 let entity = tx.load(euid)?;
526 entity.clear(&self.name);
527 Ok(())
528 }
529}
530
531#[derive(Clone)]
544pub struct AttrCommandRollFromVariable {
545 pub name: String,
546 pub var: String,
547}
548
549impl AttrCommand for AttrCommandRollFromVariable {
550 fn apply(
551 &self,
552 _ctx: &mut Context,
553 builder: &SandboxBuilder,
554 tx: &mut ReadWriteTransaction,
555 euid: &str,
556 ) -> Result<()> {
557 let value = builder.sandbox.globals[&self.var]
558 .as_array()
559 .ok_or(anyhow!("Unable to find {}", self.var))?;
560 let entity = tx.load(euid)?;
561 entity[&self.name] = builder.randomizer.choose(value).to_owned();
562 Ok(())
563 }
564
565 fn revert(
566 &self,
567 _ctx: &mut Context,
568 _builder: &SandboxBuilder,
569 tx: &mut ReadWriteTransaction,
570 euid: &str,
571 ) -> Result<()> {
572 let entity = tx.load(euid)?;
573 entity.clear(&self.name);
574 Ok(())
575 }
576}
577
578#[derive(Clone)]
600pub struct AttrCommandUseEntity {
601 pub name: String,
602 pub class_names: ClassNamesToRoll,
603 pub min: CardinalityValue,
604 pub max: CardinalityValue,
605 injectors: Injectors,
606}
607
608impl EntityAssigner for AttrCommandUseEntity {
609 fn new(
610 name: String,
611 class_names: ClassNamesToRoll,
612 min: CardinalityValue,
613 max: CardinalityValue,
614 injectors: Injectors,
615 ) -> Self {
616 AttrCommandUseEntity {
617 name,
618 class_names,
619 min,
620 max,
621 injectors,
622 }
623 }
624}
625
626impl AttrCommand for AttrCommandUseEntity {
627 fn apply(
628 &self,
629 ctx: &mut Context,
630 builder: &SandboxBuilder,
631 tx: &mut ReadWriteTransaction,
632 euid: &str,
633 ) -> Result<()> {
634 let entity = tx.load(euid)?;
635 if entity.is_missing(&self.name) {
636 entity[&self.name] =
637 serde_json::to_value(Vec::new() as Vec<serde_json::Value>).unwrap();
638 }
639 let (min, max) = match ctx {
640 Context::Appending(_) => (1, 1),
641 Context::Rolling => (
642 resolve_value(builder, &self.min),
643 resolve_value(builder, &self.max),
644 ),
645 _ => return Err(anyhow!("Invalid context when applying use: {:#?}", ctx)),
646 };
647 let class_names = match &self.class_names {
648 ClassNamesToRoll::List(l) => l,
649 _ => unreachable!(),
650 };
651 for _ in 0..builder.randomizer.in_range(min, max) {
652 let cls = builder.randomizer.choose::<String>(class_names);
653 if let Ok(Some(selected_uid)) = use_collected(builder, tx, euid, cls) {
654 for injector in self.injectors.appenders.as_slice() {
655 injector.inject(builder, tx, &selected_uid, euid)?;
656 }
657 add_user_to_entity(tx, &selected_uid, euid, &self.name)?;
658 {
659 let entity = tx.load(euid)?;
660 let list = entity[&self.name].as_array_mut().unwrap();
661 list.push(serde_json::to_value(selected_uid)?);
662 }
663 }
664 }
665 Ok(())
667 }
668
669 fn revert(
670 &self,
671 ctx: &mut Context,
672 builder: &SandboxBuilder,
673 tx: &mut ReadWriteTransaction,
674 euid: &str,
675 ) -> Result<()> {
676 if *ctx != Context::Unrolling {
677 return Err(anyhow!(
678 "Reverting a use entity command is only allowed with Context::Unrolling"
679 ));
680 }
681 let entity = tx.load(euid)?;
682 let uids_in_use = entity[&self.name].as_array().unwrap();
683 for uid_in_use in uids_in_use.clone() {
684 let uid_in_use = uid_in_use.as_str().unwrap();
685 for injector in self.injectors.appenders.as_slice() {
686 injector.eject(builder, tx, uid_in_use, euid)?;
687 }
688 if let Ok(entity_in_use) = tx.load(uid_in_use) {
689 let entity_in_use_class_name = entity_in_use["class"].as_str().unwrap().to_string();
690 entity_in_use["$users"]
691 .as_array_mut()
692 .unwrap()
693 .retain(|user| !(user["uid"] == euid && user["attr"] == self.name));
694 tx.save(uid_in_use)?;
695 recycle(tx, euid, uid_in_use, &entity_in_use_class_name)?;
696 }
697 }
698 Ok(())
700 }
701}
702
703#[derive(Clone)]
726pub struct AttrCommandPickEntity {
727 pub name: String,
728 pub class_names: ClassNamesToRoll,
729 pub min: CardinalityValue,
730 pub max: CardinalityValue,
731 injectors: Injectors,
732}
733
734impl EntityAssigner for AttrCommandPickEntity {
735 fn new(
736 name: String,
737 class_names: ClassNamesToRoll,
738 min: CardinalityValue,
739 max: CardinalityValue,
740 injectors: Injectors,
741 ) -> Self {
742 AttrCommandPickEntity {
743 name,
744 class_names,
745 min,
746 max,
747 injectors,
748 }
749 }
750}
751
752impl AttrCommand for AttrCommandPickEntity {
753 fn apply(
754 &self,
755 ctx: &mut Context,
756 builder: &SandboxBuilder,
757 tx: &mut ReadWriteTransaction,
758 euid: &str,
759 ) -> Result<()> {
760 let entity = tx.load(euid)?;
761 if entity.is_missing(&self.name) {
762 entity[&self.name] =
763 serde_json::to_value(Vec::new() as Vec<serde_json::Value>).unwrap();
764 }
765 let (min, max) = match ctx {
766 Context::Appending(_) => (1, 1),
767 Context::Rolling => (
768 resolve_value(builder, &self.min),
769 resolve_value(builder, &self.max),
770 ),
771 _ => return Err(anyhow!("Invalid context when applying pick: {:#?}", ctx)),
772 };
773
774 let class_names = match &self.class_names {
775 ClassNamesToRoll::List(l) => l,
776 _ => unreachable!(),
777 };
778 let mut uniqueness_check_set: HashSet<String> = HashSet::new();
779 for _ in 0..builder.randomizer.in_range(min, max) {
780 let cls = builder.randomizer.choose::<String>(class_names);
781 if let Ok(Some(selected_uid)) = pick_collected(builder, tx, euid, cls) {
782 if !uniqueness_check_set.insert(selected_uid.clone()) {
783 continue;
784 }
785 for injector in self.injectors.appenders.as_slice() {
786 injector.inject(builder, tx, &selected_uid, euid)?;
787 }
788
789 add_user_to_entity(tx, &selected_uid, euid, &self.name)?;
790 let entity = tx.load(euid)?;
791 let list = entity[&self.name].as_array_mut().unwrap();
792 list.push(serde_json::to_value(selected_uid)?);
793 }
794 }
795 Ok(())
796 }
797
798 fn revert(
799 &self,
800 ctx: &mut Context,
801 builder: &SandboxBuilder,
802 tx: &mut ReadWriteTransaction,
803 euid: &str,
804 ) -> Result<()> {
805 if *ctx != Context::Unrolling {
806 return Err(anyhow!(
807 "Reverting a pick entity command is only allowed with Context::Unrolling"
808 ));
809 }
810 let entity = tx.load(euid)?;
811 let uids_in_use = entity[&self.name].as_array().unwrap();
812 for uid_in_use in uids_in_use.clone() {
813 let uid_in_use = uid_in_use.as_str().unwrap();
814 for injector in self.injectors.appenders.as_slice() {
815 injector.eject(builder, tx, uid_in_use, euid)?;
816 }
817 if let Ok(entity_in_use) = tx.load(uid_in_use) {
818 entity_in_use["$users"]
819 .as_array_mut()
820 .unwrap()
821 .retain(|user| !(user["uid"] == euid && user["attr"] == self.name));
822 tx.save(uid_in_use)?;
823 }
824 }
825 Ok(())
826 }
827}
828
829#[derive(Clone)]
837pub struct InjectCommandSetValue {
838 pub name: String,
839 pub value: serde_json::Value,
840}
841
842impl ValueAssigner for InjectCommandSetValue {
843 fn new(name: String, value: serde_json::Value) -> Self {
844 InjectCommandSetValue { name, value }
845 }
846}
847
848impl InjectCommand for InjectCommandSetValue {
849 fn inject(
850 &self,
851 _builder: &SandboxBuilder,
852 tx: &mut ReadWriteTransaction,
853 euid: &str,
854 _caller: &str,
855 ) -> Result<()> {
856 let entity = tx.load(euid)?;
857 entity[&self.name] = self.value.clone();
858 Ok(())
859 }
860 fn eject(
861 &self,
862 _builder: &SandboxBuilder,
863 tx: &mut ReadWriteTransaction,
864 euid: &str,
865 _caller: &str,
866 ) -> Result<()> {
867 let entity = tx.load(euid)?;
868 entity[&self.name] = serde_json::Value::from(false);
869 Ok(())
870 }
871}
872
873#[derive(Clone)]
881pub struct InjectCommandDiceRoll {
882 pub name: String,
883 pub number_of_dice: i32,
884 pub dice_type: i32,
885 pub dice_modifier: i32,
886}
887
888impl InjectCommand for InjectCommandDiceRoll {
889 fn inject(
890 &self,
891 builder: &SandboxBuilder,
892 tx: &mut ReadWriteTransaction,
893 euid: &str,
894 _caller: &str,
895 ) -> Result<()> {
896 let entity = tx.load(euid)?;
897 let mut total: i32 = 0;
898 for _ in 0..self.number_of_dice {
899 total += builder.randomizer.in_range(1, self.dice_type);
900 }
901 total += self.dice_modifier;
902 entity[&self.name] = serde_json::to_value(total).unwrap();
903 Ok(())
904 }
905 fn eject(
906 &self,
907 _builder: &SandboxBuilder,
908 tx: &mut ReadWriteTransaction,
909 euid: &str,
910 _caller: &str,
911 ) -> Result<()> {
912 let entity = tx.load(euid)?;
913 entity[&self.name] = serde_json::Value::from(false);
914 Ok(())
915 }
916}
917
918#[derive(Clone)]
929pub struct InjectCommandRollFromList {
930 pub name: String,
931 pub list: Vec<serde_json::Value>,
932}
933
934impl InjectCommand for InjectCommandRollFromList {
935 fn inject(
936 &self,
937 builder: &SandboxBuilder,
938 tx: &mut ReadWriteTransaction,
939 euid: &str,
940 _caller: &str,
941 ) -> Result<()> {
942 let entity = tx.load(euid)?;
943 entity[&self.name] = builder.randomizer.choose(&self.list).to_owned();
944 Ok(())
945 }
946 fn eject(
947 &self,
948 _builder: &SandboxBuilder,
949 tx: &mut ReadWriteTransaction,
950 euid: &str,
951 _caller: &str,
952 ) -> Result<()> {
953 let entity = tx.load(euid)?;
954 entity.clear(&self.name);
955 Ok(())
956 }
957}
958
959#[derive(Clone)]
971pub struct InjectCommandCopyValue {
972 pub name: String,
973 pub path: Vec<String>,
974}
975
976impl RefInjectCommand for InjectCommandCopyValue {
977 fn make(name: String, path: Vec<String>) -> Arc<dyn InjectCommand + Send + Sync> {
978 Arc::new(InjectCommandCopyValue { name, path })
979 }
980}
981
982impl InjectCommand for InjectCommandCopyValue {
983 fn inject(
984 &self,
985 _builder: &SandboxBuilder,
986 tx: &mut ReadWriteTransaction,
987 euid: &str,
988 caller: &str,
989 ) -> Result<()> {
990 let value = {
991 if let Some((pointer_uid, pointer_attr_name)) = walk_path(caller, &self.path, tx)? {
992 let src = tx.load(pointer_uid.as_str().unwrap())?;
993 src[pointer_attr_name.as_str().unwrap()].clone()
994 } else {
995 serde_json::Value::from(false)
996 }
997 };
998 let entity = tx.load(euid)?;
999 entity[&self.name] = value;
1000 Ok(())
1001 }
1002 fn eject(
1003 &self,
1004 _builder: &SandboxBuilder,
1005 tx: &mut ReadWriteTransaction,
1006 euid: &str,
1007 _caller: &str,
1008 ) -> Result<()> {
1009 let entity = tx.load(euid)?;
1010 entity[&self.name] = serde_json::Value::from(false);
1011 Ok(())
1012 }
1013}
1014
1015pub struct InjectCommandPtr {
1029 pub name: String,
1030 pub path: Vec<String>,
1031}
1032
1033impl RefInjectCommand for InjectCommandPtr {
1034 fn make(name: String, path: Vec<String>) -> Arc<dyn InjectCommand + Send + Sync> {
1035 Arc::new(InjectCommandPtr { name, path })
1036 }
1037}
1038
1039impl InjectCommand for InjectCommandPtr {
1040 fn inject(
1041 &self,
1042 _builder: &SandboxBuilder,
1043 tx: &mut ReadWriteTransaction,
1044 euid: &str,
1045 caller: &str,
1046 ) -> Result<()> {
1047 if let Some((pointer_uid, pointer_attr_name)) = walk_path(caller, &self.path, tx)? {
1048 let value = serde_json::json!({
1049 "type": "pointer",
1050 "spec": {
1051 "uid": pointer_uid,
1052 "attr": pointer_attr_name
1053 }
1054 });
1055 let entity = tx.load(euid)?;
1056 entity[&self.name] = value;
1057 add_user_to_entity(tx, pointer_uid.as_str().unwrap(), euid, &self.name)?;
1058 Ok(())
1059 } else {
1060 Err(anyhow!(
1061 "walking an attribute path failed for {}",
1062 self.name
1063 ))
1064 }
1065 }
1066 fn eject(
1067 &self,
1068 _builder: &SandboxBuilder,
1069 tx: &mut ReadWriteTransaction,
1070 euid: &str,
1071 _caller: &str,
1072 ) -> Result<()> {
1073 let entity = tx.load(euid)?;
1074 entity[&self.name] = serde_json::Value::from(false);
1075 Ok(())
1076 }
1077}
1078
1079fn add_user_to_entity(
1093 tx: &mut ReadWriteTransaction,
1094 uid: &str,
1095 user_uid: &str,
1096 user_attr: &str,
1097) -> Result<()> {
1098 let selected_entity = tx.load(uid)?;
1099 if selected_entity.is_missing("$users") {
1100 selected_entity["$users"] = serde_json::json!([]);
1101 }
1102 selected_entity["$users"]
1103 .as_array_mut()
1104 .unwrap()
1105 .push(serde_json::json!({
1106 "uid": user_uid,
1107 "attr": user_attr,
1108 }));
1109 tx.save(uid)?;
1110 Ok(())
1111}
1112
1113fn walk_path(
1122 starting_uid: &str,
1123 path: &[String],
1124 tx: &mut ReadWriteTransaction,
1125) -> Result<Option<(serde_json::Value, serde_json::Value)>> {
1126 let mut pointer_uid: serde_json::Value = serde_json::json!(starting_uid);
1127 let mut pointer_attr_name = serde_json::to_value(path.first()).unwrap();
1128 for (index, path_part) in path.iter().enumerate() {
1129 let src = tx.load(pointer_uid.as_str().unwrap())?;
1130 let pointed_value = &src[path_part];
1131 if index == path.len() - 1 {
1132 pointer_attr_name = serde_json::to_value(path_part).unwrap();
1133 } else if let Some(value_as_array) = pointed_value.as_array() {
1134 if value_as_array.is_empty() {
1135 return Ok(None);
1136 }
1137 pointer_uid = value_as_array.first().unwrap().clone();
1138 } else {
1139 pointer_attr_name = serde_json::to_value(path_part).unwrap();
1140 }
1141 }
1142 Ok(Some((pointer_uid, pointer_attr_name)))
1143}
1144
1145fn resolve_value(builder: &SandboxBuilder, cv: &CardinalityValue) -> i32 {
1150 match cv {
1151 CardinalityValue::Number(n) => *n,
1152 CardinalityValue::Variable(v) => {
1153 log::info!("{}", v);
1154 builder.sandbox.globals.get(v).unwrap().as_i64().unwrap() as i32
1155 }
1156 CardinalityValue::Undefined => 1,
1157 }
1158}