Struct IdleAction

Source
pub struct IdleAction { /* private fields */ }
Expand description

A state machine that performs an action during idle periods.

This could be used to invoke std::thread::sleep during idle periods to save CPU time.

Implementations§

Source§

impl IdleAction

Source

pub fn new(thresh: usize, action: Box<dyn FnMut()>) -> Self

Creates a new IdleAction that triggers automatically after max_yields idle steps.

Examples found in repository?
examples/basic.rs (line 136)
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}
Source

pub fn consume<C: CustomTypes<S>, S: System<C>>( &mut self, res: &ProjectStep<'_, C, S>, )

Consumes a step result and advances the state machine. If the step resulting in an idle action, this may trigger the idle action to fire and reset the state machine.

Examples found in repository?
examples/basic.rs (line 150)
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}
Source

pub fn trigger(&mut self)

Explicitly triggers the idle action and reset the state machine.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,