pub struct StdSystem<C: CustomTypes<StdSystem<C>>> { /* private fields */ }
Expand description
A type implementing the System
trait which supports all features.
StdSystem
can be configured with CustomTypes
and Config
,
which together allow for the definition of any external features (e.g., defining syscalls),
as well as overriding default behavior (e.g., rpc intercepting).
Implementations§
Source§impl<C: CustomTypes<StdSystem<C>>> StdSystem<C>
impl<C: CustomTypes<StdSystem<C>>> StdSystem<C>
Sourcepub fn new_sync(
base_url: CompactString,
project_name: Option<&str>,
config: Config<C, Self>,
clock: Arc<Clock>,
) -> Self
pub fn new_sync( base_url: CompactString, project_name: Option<&str>, config: Config<C, Self>, clock: Arc<Clock>, ) -> Self
Equivalent to StdSystem::new_async
except that it can be executed outside of async context.
Note that using this from within async context can result in a panic from, e.g., tokio
trying to create a runtime within a runtime.
Examples found in repository?
99fn main() {
100 // read in an xml file whose path is given as a command line argument
101 let args = std::env::args().collect::<Vec<_>>();
102 if args.len() != 2 {
103 panic!("usage: {} [xml file]", &args[0]);
104 }
105 let mut xml = String::new();
106 std::fs::File::open(&args[1]).expect("failed to open file").read_to_string(&mut xml).expect("failed to read file");
107
108 // create a new shared clock and start a thread that updates it at our desired interval
109 let clock = Arc::new(Clock::new(UtcOffset::UTC, Some(Precision::Medium)));
110 let clock_clone = clock.clone();
111 std::thread::spawn(move || loop {
112 std::thread::sleep(CLOCK_INTERVAL);
113 clock_clone.update();
114 });
115
116 // create a custom config for the system - in this simple example we just implement the say/think blocks to print to stdout
117 let config = Config::<C, StdSystem<C>> {
118 request: None,
119 command: Some(Rc::new(|_mc, key, command, _proc| match command {
120 Command::Print { style: _, value } => {
121 if let Some(value) = value {
122 println!("{value:?}");
123 }
124 key.complete(Ok(())); // any request that you handle must be completed - otherwise the calling process will hang forever
125 CommandStatus::Handled
126 }
127 _ => CommandStatus::UseDefault { key, command }, // anything you don't handle should return the key and command to invoke the default behavior instead
128 })),
129 };
130
131 // initialize our system with all the info we've put together
132 let system = Rc::new(StdSystem::new_sync(CompactString::new(BASE_URL), None, config, clock.clone()));
133 let mut env = get_running_project(&xml, system);
134
135 // begin running the code - these are some helpers to make things more efficient in terms of memory and cpu resources
136 let mut idle_sleeper = IdleAction::new(YIELDS_BEFORE_SLEEP, Box::new(|| std::thread::sleep(IDLE_SLEEP_TIME)));
137 let mut next_collect = clock.read(Precision::Medium) + COLLECT_INTERVAL;
138 loop {
139 env.mutate(|mc, env| {
140 let mut proj = env.proj.borrow_mut(mc);
141 for _ in 0..1024 {
142 // step the virtual machine forward by one bytecode instruction
143 let res = proj.step(mc);
144 if let ProjectStep::Error { error, proc } = &res {
145 // if we get an error, we can generate an error summary including a stack trace - here we just print out the result
146 let trace = ErrorSummary::extract(error, proc, &env.locs);
147 println!("error: {error:?}\ntrace: {trace:?}");
148 }
149 // this takes care of performing thread sleep if we get a bunch of no-ops from proj.step back to back
150 idle_sleeper.consume(&res);
151 }
152 });
153 // if it's time for us to do garbage collection, do it and reset the next collection time
154 if clock.read(Precision::Low) >= next_collect {
155 env.collect_all();
156 next_collect = clock.read(Precision::Medium) + COLLECT_INTERVAL;
157 }
158 }
159}
Sourcepub async fn new_async(
base_url: CompactString,
project_name: Option<&str>,
config: Config<C, Self>,
clock: Arc<Clock>,
) -> Self
pub async fn new_async( base_url: CompactString, project_name: Option<&str>, config: Config<C, Self>, clock: Arc<Clock>, ) -> Self
Initializes a new instance of StdSystem
targeting the given NetsBlox server base url, e.g., https://cloud.netsblox.org
.
Sourcepub async fn call_rpc_async(
&self,
host: Option<&str>,
service: &str,
rpc: &str,
args: &[(&str, &Json)],
) -> Result<SimpleValue, CompactString>
pub async fn call_rpc_async( &self, host: Option<&str>, service: &str, rpc: &str, args: &[(&str, &Json)], ) -> Result<SimpleValue, CompactString>
Asynchronously calls an RPC and returns the result.
This function directly makes requests to NetsBlox, bypassing any RPC hook defined by Config
.
Sourcepub fn get_public_id(&self) -> CompactString
pub fn get_public_id(&self) -> CompactString
Gets the public id of the running system that can be used to send messages to this client.
Sourcepub fn inject_message(
&self,
msg_type: CompactString,
values: VecMap<CompactString, SimpleValue, false>,
)
pub fn inject_message( &self, msg_type: CompactString, values: VecMap<CompactString, SimpleValue, false>, )
Injects a message into the receiving queue as if received over the network.
Trait Implementations§
Source§impl<C: CustomTypes<StdSystem<C>>> System<C> for StdSystem<C>
impl<C: CustomTypes<StdSystem<C>>> System<C> for StdSystem<C>
Source§type RequestKey = AsyncKey<Result<<C as CustomTypes<StdSystem<C>>>::Intermediate, CompactString>>
type RequestKey = AsyncKey<Result<<C as CustomTypes<StdSystem<C>>>::Intermediate, CompactString>>
Source§type CommandKey = AsyncKey<Result<(), CompactString>>
type CommandKey = AsyncKey<Result<(), CompactString>>
Source§fn rand<T: SampleUniform, R: SampleRange<T>>(&self, range: R) -> T
fn rand<T: SampleUniform, R: SampleRange<T>>(&self, range: R) -> T
range
, which is assumed to be non-empty.
The input for this generic function is such that it is compatible with rand::Rng::gen_range
,
which makes it possible to implement this function with any random provider under the rand
crate standard.Source§fn perform_request<'gc>(
&self,
mc: &Mutation<'gc>,
request: Request<'gc, C, Self>,
proc: &mut Process<'gc, C, Self>,
) -> Result<Self::RequestKey, ErrorCause<C, Self>>
fn perform_request<'gc>( &self, mc: &Mutation<'gc>, request: Request<'gc, C, Self>, proc: &mut Process<'gc, C, Self>, ) -> Result<Self::RequestKey, ErrorCause<C, Self>>
Entity
that made the request is provided for context.Source§fn poll_request<'gc>(
&self,
mc: &Mutation<'gc>,
key: &Self::RequestKey,
_proc: &mut Process<'gc, C, Self>,
) -> Result<AsyncResult<Result<Value<'gc, C, Self>, CompactString>>, ErrorCause<C, Self>>
fn poll_request<'gc>( &self, mc: &Mutation<'gc>, key: &Self::RequestKey, _proc: &mut Process<'gc, C, Self>, ) -> Result<AsyncResult<Result<Value<'gc, C, Self>, CompactString>>, ErrorCause<C, Self>>
Entity
that made the request is provided for context.Source§fn perform_command<'gc>(
&self,
mc: &Mutation<'gc>,
command: Command<'gc, '_, C, Self>,
proc: &mut Process<'gc, C, Self>,
) -> Result<Self::CommandKey, ErrorCause<C, Self>>
fn perform_command<'gc>( &self, mc: &Mutation<'gc>, command: Command<'gc, '_, C, Self>, proc: &mut Process<'gc, C, Self>, ) -> Result<Self::CommandKey, ErrorCause<C, Self>>
Entity
that issued the command is provided for context.Source§fn poll_command<'gc>(
&self,
_mc: &Mutation<'gc>,
key: &Self::CommandKey,
_proc: &mut Process<'gc, C, Self>,
) -> Result<AsyncResult<Result<(), CompactString>>, ErrorCause<C, Self>>
fn poll_command<'gc>( &self, _mc: &Mutation<'gc>, key: &Self::CommandKey, _proc: &mut Process<'gc, C, Self>, ) -> Result<AsyncResult<Result<(), CompactString>>, ErrorCause<C, Self>>
Entity
that issued the command is provided for context.Source§fn send_message(
&self,
msg_type: CompactString,
values: VecMap<CompactString, Json, false>,
targets: Vec<CompactString>,
expect_reply: bool,
) -> Result<Option<ExternReplyKey>, ErrorCause<C, StdSystem<C>>>
fn send_message( &self, msg_type: CompactString, values: VecMap<CompactString, Json, false>, targets: Vec<CompactString>, expect_reply: bool, ) -> Result<Option<ExternReplyKey>, ErrorCause<C, StdSystem<C>>>
values
to each of the specified targets
.
The expect_reply
value controls whether or not to use a reply mechanism to asynchronously receive a response from the target(s).
In the case that there are multiple targets, only the first reply (if any) should be used.Source§fn poll_reply(&self, key: &ExternReplyKey) -> AsyncResult<Option<Json>>
fn poll_reply(&self, key: &ExternReplyKey) -> AsyncResult<Option<Json>>
System::send_message
.
If the client responds, a value of [Some(x)
] is returned.
The system may elect to impose a timeout for reply results, in which case None
is returned instead.Source§fn send_reply(
&self,
key: InternReplyKey,
value: Json,
) -> Result<(), ErrorCause<C, Self>>
fn send_reply( &self, key: InternReplyKey, value: Json, ) -> Result<(), ErrorCause<C, Self>>
Source§fn receive_message(&self) -> Option<IncomingMessage>
fn receive_message(&self) -> Option<IncomingMessage>
None
if there are no messages in the buffer.
If a message is received, a tuple of form (msg_type, values, reply_key)
is returned.