diff --git a/src/bytecode.rs b/src/bytecode.rs index 6d808bc..e4ef8a8 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -150,7 +150,7 @@ impl BasicType { } } -pub(crate) enum InternalInstruction<'a> { +enum InternalInstruction<'a> { /// Triggers an error when encountered. /// This is an internal value that is only used to denote incomplete linking results for better testing. /// Properly-linked byte code should not contain this value. diff --git a/src/lib.rs b/src/lib.rs index d90405a..cb6fc04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ extern crate std; #[macro_use] extern crate alloc; #[macro_use] extern crate num_derive; -pub(crate) use educe::Educe; +use educe::Educe; /// Re-exports of relevant items from `gc_arena`. pub mod gc { diff --git a/src/process.rs b/src/process.rs index 343b1ae..f211ce4 100644 --- a/src/process.rs +++ b/src/process.rs @@ -144,7 +144,7 @@ pub enum ProcessStep<'gc, C: CustomTypes, S: System> { /// This contains information about the call origin and local variables defined in the called context. #[derive(Collect)] #[collect(no_drop, bound = "")] -pub struct CallStackEntry<'gc, C: CustomTypes, S: System> { +struct CallStackEntry<'gc, C: CustomTypes, S: System> { #[collect(require_static)] called_from: usize, #[collect(require_static)] return_to: usize, entity: Gc<'gc, RefLock>>, @@ -212,8 +212,7 @@ pub struct Process<'gc, C: CustomTypes, S: System> { last_message: Option>, } impl<'gc, C: CustomTypes, S: System> Process<'gc, C, S> { - /// Creates a new [`Process`] that is tied to a given `start_pos` (entry point) in the [`ByteCode`] and associated with the specified `entity` and `system`. - /// The created process is initialized to an idle (non-running) state; use [`Process::initialize`] to begin execution. + /// Creates a new [`Process`] with the given starting context. pub fn new(context: ProcContext<'gc, C, S>) -> Self { Self { global_context: context.global_context, @@ -460,9 +459,9 @@ impl<'gc, C: CustomTypes, S: System> Process<'gc, C, S> { self.value_stack.push(lookup_var!(var).get().clone()); self.pos = aft_pos; } - Instruction::PushEntity { name } => match global_context.entities.iter().find(|&x| x.borrow().name.as_str() == name) { + Instruction::PushEntity { name } => match global_context.entities.iter().find(|&x| x.0 == name) { Some(x) => { - self.value_stack.push(Value::Entity(*x)); + self.value_stack.push(Value::Entity(x.1)); self.pos = aft_pos; } None => return Err(ErrorCause::UndefinedEntity { name: name.into() }), diff --git a/src/project.rs b/src/project.rs index 53e80ce..f08a016 100644 --- a/src/project.rs +++ b/src/project.rs @@ -95,39 +95,41 @@ pub enum ProjectStep<'gc, C: CustomTypes, S: System> { Pause, } +#[derive(Collect, Educe)] +#[collect(no_drop, bound = "")] +#[educe(Clone, Default)] +pub struct PartialProcContext<'gc, C: CustomTypes, S: System> { + pub locals: SymbolTable<'gc, C, S>, + #[collect(require_static)] pub barrier: Option, + #[collect(require_static)] pub reply_key: Option, + #[collect(require_static)] pub local_message: Option, +} + #[derive(Collect)] #[collect(no_drop, bound = "")] struct Script<'gc, C: CustomTypes, S: System> { #[collect(require_static)] event: Rc<(Event, usize)>, // event and bytecode start pos entity: Gc<'gc, RefLock>>, #[collect(require_static)] process: Option, - context_queue: VecDeque>, + context_queue: VecDeque>, } impl<'gc, C: CustomTypes, S: System> Script<'gc, C, S> { fn consume_context(&mut self, state: &mut State<'gc, C, S>) { let process = self.process.and_then(|key| Some((key, state.processes.get_mut(key)?))); - if process.as_ref().map(|x| x.1.is_running()).unwrap_or(false) { return } - - let context = match self.context_queue.pop_front() { - Some(x) => x, - None => return, - }; - match process { - Some((key, process)) => { - debug_assert!(!state.process_queue.contains(&key)); - debug_assert_eq!(self.process, Some(key)); - - process.initialize(context); - state.process_queue.push_back(key); - } - None => { - let mut process = Process::new(state.global_context, self.entity, self.event.1); - process.initialize(context); - let key = state.processes.insert(process); - state.process_queue.push_back(key); - self.process = Some(key); + Some(proc) => match proc.1.is_running() { + true => return, + false => unreachable!(), // should have already been cleaned up by the scheduler } + None => match self.context_queue.pop_front() { + None => return, + Some(context) => { + let process = Process::new(ProcContext { global_context: state.global_context, entity: self.entity, start_pos: self.event.1, locals: context.locals, barrier: context.barrier, reply_key: context.reply_key, local_message: context.local_message }); + let key = state.processes.insert(process); + state.process_queue.push_back(key); + self.process = Some(key); + } + }, } } fn stop_all(&mut self, state: &mut State<'gc, C, S>) { @@ -136,7 +138,7 @@ impl<'gc, C: CustomTypes, S: System> Script<'gc, C, S> { } self.context_queue.clear(); } - fn schedule(&mut self, state: &mut State<'gc, C, S>, context: ProcContext<'gc, C, S>, max_queue: usize) { + fn schedule(&mut self, state: &mut State<'gc, C, S>, context: PartialProcContext<'gc, C, S>, max_queue: usize) { self.context_queue.push_back(context); self.consume_context(state); if self.context_queue.len() > max_queue { @@ -180,9 +182,9 @@ impl<'gc, C: CustomTypes, S: System> Project<'gc, C, S> { let mut project = Self::new(Gc::new(mc, RefLock::new(global_context))); for entity_info in init_info.entities.iter() { - let entity = *project.state.global_context.borrow().entities.get(&entity_info.name).unwrap(); + let entity = project.state.global_context.borrow().entities.iter().find(|&x| x.0 == entity_info.name).unwrap().1; for (event, pos) in entity_info.scripts.iter() { - project.add_script(*pos, entity, Some(event.clone())); + project.add_script(*pos, entity, event.clone()); } } @@ -198,23 +200,13 @@ impl<'gc, C: CustomTypes, S: System> Project<'gc, C, S> { scripts: Default::default(), } } - pub fn add_script(&mut self, start_pos: usize, entity: Gc<'gc, RefLock>>, event: Option) { - let mut all_contexts_consumer = AllContextsConsumer::new(); - match event { - Some(event) => self.scripts.push(Script { - event: Rc::new((event, start_pos)), - entity, - process: None, - context_queue: Default::default(), - }), - None => { - let process = Process::new(self.state.global_context, entity, start_pos); - let key = self.state.processes.insert(process); - - all_contexts_consumer.do_once(self); // need to consume all contexts before scheduling things in the future - self.state.process_queue.push_back(key); - } - } + pub fn add_script(&mut self, start_pos: usize, entity: Gc<'gc, RefLock>>, event: Event) { + self.scripts.push(Script { + event: Rc::new((event, start_pos)), + entity, + process: None, + context_queue: Default::default(), + }); } pub fn input(&mut self, mc: &Mutation<'gc>, input: Input) { let mut all_contexts_consumer = AllContextsConsumer::new(); @@ -241,7 +233,7 @@ impl<'gc, C: CustomTypes, S: System> Project<'gc, C, S> { all_contexts_consumer.do_once(self); // need to consume all contexts before scheduling things in the future if interrupt { self.scripts[i].stop_all(&mut self.state); } - self.scripts[i].schedule(&mut self.state, ProcContext { locals, ..Default::default() }, max_queue); + self.scripts[i].schedule(&mut self.state, PartialProcContext { locals, ..Default::default() }, max_queue); } } } @@ -282,7 +274,7 @@ impl<'gc, C: CustomTypes, S: System> Project<'gc, C, S> { } all_contexts_consumer.do_once(self); // need to consume all contexts before scheduling things in the future - self.scripts[i].schedule(&mut self.state, ProcContext { locals, barrier: None, reply_key: reply_key.clone(), local_message: None }, usize::MAX); + self.scripts[i].schedule(&mut self.state, PartialProcContext { locals, barrier: None, reply_key: reply_key.clone(), local_message: None }, usize::MAX); } } } @@ -341,7 +333,7 @@ impl<'gc, C: CustomTypes, S: System> Project<'gc, C, S> { for script in new_scripts.iter_mut() { if let Event::OnClone = &script.event.0 { all_contexts_consumer.do_once(self); // need to consume all contexts before scheduling things in the future - script.schedule(&mut self.state, ProcContext::default(), 0); + script.schedule(&mut self.state, Default::default(), 0); } } self.scripts.extend(new_scripts); @@ -360,7 +352,7 @@ impl<'gc, C: CustomTypes, S: System> Project<'gc, C, S> { all_contexts_consumer.do_once(self); // need to consume all contexts before scheduling things in the future self.scripts[i].stop_all(&mut self.state); - self.scripts[i].schedule(&mut self.state, ProcContext { locals: Default::default(), barrier: barrier.clone(), reply_key: None, local_message: Some(msg_type.clone()) }, 0); + self.scripts[i].schedule(&mut self.state, PartialProcContext { locals: Default::default(), barrier: barrier.clone(), reply_key: None, local_message: Some(msg_type.clone()) }, 0); } } } diff --git a/src/runtime.rs b/src/runtime.rs index fbb0006..38fcc3c 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1085,14 +1085,14 @@ pub enum EntityKind<'gc, 'a, C: CustomTypes, S: System> { #[derive(Collect)] #[collect(no_drop, bound = "")] pub struct Entity<'gc, C: CustomTypes, S: System> { - #[collect(require_static)] pub(crate) name: Rc, - #[collect(require_static)] pub(crate) sound_list: Rc)>>, - #[collect(require_static)] pub(crate) costume_list: Rc)>>, - #[collect(require_static)] pub(crate) costume: Option>, - #[collect(require_static)] pub(crate) state: C::EntityState, - #[collect(require_static)] pub(crate) alive: bool, - pub(crate) original: Option>>>, - pub(crate) fields: SymbolTable<'gc, C, S>, + #[collect(require_static)] pub name: Rc, + #[collect(require_static)] pub sound_list: Rc)>>, + #[collect(require_static)] pub costume_list: Rc)>>, + #[collect(require_static)] pub costume: Option>, + #[collect(require_static)] pub state: C::EntityState, + #[collect(require_static)] pub alive: bool, + pub original: Option>>>, + pub fields: SymbolTable<'gc, C, S>, } impl, S: System> fmt::Debug for Entity<'_, C, S> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1341,7 +1341,7 @@ pub struct GlobalContext<'gc, C: CustomTypes, S: System> { #[collect(require_static)] pub timer_start: u64, #[collect(require_static)] pub proj_name: String, pub globals: SymbolTable<'gc, C, S>, - pub entities: Vec>>>, + pub entities: Vec<(String, Gc<'gc, RefLock>>)>, } impl<'gc, C: CustomTypes, S: System> GlobalContext<'gc, C, S> { pub fn from_init(mc: &Mutation<'gc>, init_info: &InitInfo, bytecode: Rc, settings: Settings, system: Rc) -> Self { @@ -1431,7 +1431,7 @@ impl<'gc, C: CustomTypes, S: System> GlobalContext<'gc, C, S> { let name = Rc::new(entity_info.name.clone()); let state = kind.into(); - entities.push(Gc::new(mc, RefLock::new(Entity { alive: true, original: None, name, fields, sound_list, costume_list, costume, state }))); + entities.push(((*name).clone(), Gc::new(mc, RefLock::new(Entity { alive: true, original: None, name, fields, sound_list, costume_list, costume, state })))); } let proj_name = init_info.proj_name.clone(); diff --git a/src/std_system.rs b/src/std_system.rs index 1f26232..5e19961 100644 --- a/src/std_system.rs +++ b/src/std_system.rs @@ -69,7 +69,7 @@ struct ReplyEntry { /// A [`StdSystem`] key type for an asynchronous request. pub struct RequestKey>>(Arc>>>); impl>> RequestKey { - pub(crate) fn poll(&self) -> AsyncResult> { self.0.lock().unwrap().poll() } + fn poll(&self) -> AsyncResult> { self.0.lock().unwrap().poll() } } impl>> Key> for RequestKey { /// Completes the request with the given result. @@ -85,7 +85,7 @@ impl>> Key> for Requ /// A [`StdSystem`] key type for an asynchronous command. pub struct CommandKey(Arc>>>); impl CommandKey { - pub(crate) fn poll(&self) -> AsyncResult> { self.0.lock().unwrap().poll() } + fn poll(&self) -> AsyncResult> { self.0.lock().unwrap().poll() } } impl Key> for CommandKey { /// Completes the command. diff --git a/src/test/process.rs b/src/test/process.rs index 8d91c28..bfca0d5 100644 --- a/src/test/process.rs +++ b/src/test/process.rs @@ -26,7 +26,7 @@ struct Env<'gc> { } type EnvArena = Arena]>; -fn get_running_proc<'a, F>(xml: &'a str, settings: Settings, system: Rc>, locals: F) -> (EnvArena, Locations) where F: for<'gc> Fn(&Mutation<'gc>) -> SymbolTable<'gc, C, StdSystem>{ +fn get_running_proc<'a, F>(xml: &'a str, settings: Settings, system: Rc>, locals: F) -> (EnvArena, Locations) where F: for<'gc> FnOnce(&Mutation<'gc>) -> SymbolTable<'gc, C, StdSystem>{ let parser = ast::Parser::default(); let ast = parser.parse(xml).unwrap(); assert_eq!(ast.roles.len(), 1); @@ -36,10 +36,10 @@ fn get_running_proc<'a, F>(xml: &'a str, settings: Settings, system: Rc0"#, fields = "", funcs = include_str!("blocks/warp-yields.xml"), methods = "", - ), Settings::default(), system, |_| locals); + ), Settings::default(), system.clone(), |_| { + let mut locals = SymbolTable::default(); + locals.define_or_redefine("mode", Shared::Unique(Number::new(mode as f64).unwrap().into())); + locals + }); run_till_term(&mut env, |mc, env, res| { let (res, yields) = res.unwrap(); @@ -550,16 +554,17 @@ fn test_proc_rpc_call_basic() { let system = Rc::new(StdSystem::new_sync(BASE_URL.to_owned(), None, Config::default(), Arc::new(Clock::new(UtcOffset::UTC, None)))); for (lat, long, city) in [(36.1627, -86.7816, "Nashville"), (40.8136, -96.7026, "Lincoln"), (40.7608, -111.8910, "Salt Lake City")] { - let mut locals = SymbolTable::default(); - locals.define_or_redefine("lat", Shared::Unique(Number::new(lat).unwrap().into())); - locals.define_or_redefine("long", Shared::Unique(Number::new(long).unwrap().into())); - let (mut env, _) = get_running_proc(&format!(include_str!("templates/generic-static.xml"), globals = "", fields = "", funcs = include_str!("blocks/rpc-call-basic.xml"), methods = "", - ), Settings::default(), system, |_| locals); + ), Settings::default(), system.clone(), |_| { + let mut locals = SymbolTable::default(); + locals.define_or_redefine("lat", Shared::Unique(Number::new(lat).unwrap().into())); + locals.define_or_redefine("long", Shared::Unique(Number::new(long).unwrap().into())); + locals + }); run_till_term(&mut env, |_, _, res| match res.unwrap().0.unwrap() { Value::String(ret) => assert_eq!(&*ret, city), x => panic!("{:?}", x),