Struct AsyncTaskObject

Source
pub struct AsyncTaskObject(/* private fields */);
Expand description

Handle to a Wolfram Language AsynchronousTaskObjectWL instance.

Use spawn_with_thread() to spawn a new asynchronous task.

Implementations§

Source§

impl AsyncTaskObject

Source

pub fn spawn_with_thread<F>(f: F) -> Self
where F: FnMut(AsyncTaskObject) + Send + UnwindSafe + 'static,

Spawn a new Wolfram Language asynchronous task.

This method can be used within a LibraryLink function that was called via

Internal`CreateAsynchronousTask[
    _LibraryFunction,
    args_List,
    handler
]

to create a new AsynchronousTaskObjectWL that uses a background thread that can generate events that will be processed asynchronously by the Wolfram Language.

The background thread is given an AsyncTaskObject that has the same id as the AsyncTaskObject returned from this function. Events generated by the background thread using raise_async_event() will result in an asynchronous call to the Wolfram Language handler function specified in the call to Internal`CreateAsynchronousEvent.

Examples found in repository?
examples/async/async_file_watcher.rs (lines 21-23)
13fn start_file_watcher(pause_interval_ms: mint, path: String) -> mint {
14    let pause_interval_ms =
15        u64::try_from(pause_interval_ms).expect("mint interval overflows u64");
16
17    let path = PathBuf::from(path);
18
19    // Spawn a new thread, which will run in the background and check for file
20    // modifications.
21    let task = AsyncTaskObject::spawn_with_thread(move |task: AsyncTaskObject| {
22        file_watch_thread_function(task, pause_interval_ms, &path);
23    });
24
25    task.id()
26}
Source

pub fn id(&self) -> mint

Returns the numeric ID which identifies this async object.

Examples found in repository?
examples/async/async_file_watcher.rs (line 25)
13fn start_file_watcher(pause_interval_ms: mint, path: String) -> mint {
14    let pause_interval_ms =
15        u64::try_from(pause_interval_ms).expect("mint interval overflows u64");
16
17    let path = PathBuf::from(path);
18
19    // Spawn a new thread, which will run in the background and check for file
20    // modifications.
21    let task = AsyncTaskObject::spawn_with_thread(move |task: AsyncTaskObject| {
22        file_watch_thread_function(task, pause_interval_ms, &path);
23    });
24
25    task.id()
26}
Source

pub fn is_alive(&self) -> bool

Returns whether this async task is still alive.

LibraryLink C Function: asynchronousTaskAliveQ.

Examples found in repository?
examples/async/async_file_watcher.rs (line 78)
29fn file_watch_thread_function(
30    task: AsyncTaskObject,
31    pause_interval_ms: u64,
32    path: &PathBuf,
33) {
34    let mut prev_changed: Option<SystemTime> = fs::metadata(path)
35        .and_then(|metadata| metadata.modified())
36        .ok();
37
38    // Stateful closure which checks if the file at `path` has been modified since the
39    // last time this closure was called (and `prev_changed was updated). Using a closure
40    // simplifies the control flow in the main `loop` below, which should sleep on every
41    // iteration regardless of how this function returns.
42    let mut check_for_modification = || -> Option<_> {
43        let changed: Option<fs::Metadata> = fs::metadata(path).ok();
44
45        let notify: Option<SystemTime> = match (&prev_changed, changed) {
46            (Some(prev), Some(latest)) => {
47                let latest: SystemTime = match latest.modified() {
48                    Ok(latest) => latest,
49                    Err(_) => return None,
50                };
51
52                if *prev != latest {
53                    prev_changed = Some(latest.clone());
54                    Some(latest)
55                } else {
56                    None
57                }
58            },
59            // TODO: Notify on file removal?
60            (Some(_prev), None) => None,
61            (None, Some(latest)) => latest.modified().ok(),
62            (None, None) => None,
63        };
64
65        let time = notify?;
66
67        let since_epoch = match time.duration_since(std::time::UNIX_EPOCH) {
68            Ok(duration) => duration,
69            Err(_) => return None,
70        };
71
72        let since_epoch = since_epoch.as_secs();
73
74        Some(since_epoch)
75    };
76
77    loop {
78        if !task.is_alive() {
79            break;
80        }
81
82        // Check to see if the file has been modified. If it has, raise an async event
83        // called "change", and attach the modification timestamp as event data.
84        if let Some(modification) = check_for_modification() {
85            let mut data = DataStore::new();
86            data.add_i64(modification as i64);
87
88            task.raise_async_event("change", data);
89        }
90
91        // Wait for a bit before polling again for any changes to the file.
92        std::thread::sleep(Duration::from_millis(pause_interval_ms));
93    }
94}
Source

pub fn is_started(&self) -> bool

Returns whether this async task has been started.

LibraryLink C Function: asynchronousTaskStartedQ.

Source

pub fn raise_async_event(&self, name: &str, data: DataStore)

Raise a new named asynchronous event associated with the current async task.

§Example

Raise a new asynchronous event with no associated data:

This will cause the Wolfram Language event handler associated with this task to be run.

LibraryLink C Function: raiseAsyncEvent.

use wolfram_library_link::{AsyncTaskObject, DataStore};

let task_object: AsyncTaskObject = todo!();

task_object.raise_async_event("change", DataStore::new());
Examples found in repository?
examples/async/async_file_watcher.rs (line 88)
29fn file_watch_thread_function(
30    task: AsyncTaskObject,
31    pause_interval_ms: u64,
32    path: &PathBuf,
33) {
34    let mut prev_changed: Option<SystemTime> = fs::metadata(path)
35        .and_then(|metadata| metadata.modified())
36        .ok();
37
38    // Stateful closure which checks if the file at `path` has been modified since the
39    // last time this closure was called (and `prev_changed was updated). Using a closure
40    // simplifies the control flow in the main `loop` below, which should sleep on every
41    // iteration regardless of how this function returns.
42    let mut check_for_modification = || -> Option<_> {
43        let changed: Option<fs::Metadata> = fs::metadata(path).ok();
44
45        let notify: Option<SystemTime> = match (&prev_changed, changed) {
46            (Some(prev), Some(latest)) => {
47                let latest: SystemTime = match latest.modified() {
48                    Ok(latest) => latest,
49                    Err(_) => return None,
50                };
51
52                if *prev != latest {
53                    prev_changed = Some(latest.clone());
54                    Some(latest)
55                } else {
56                    None
57                }
58            },
59            // TODO: Notify on file removal?
60            (Some(_prev), None) => None,
61            (None, Some(latest)) => latest.modified().ok(),
62            (None, None) => None,
63        };
64
65        let time = notify?;
66
67        let since_epoch = match time.duration_since(std::time::UNIX_EPOCH) {
68            Ok(duration) => duration,
69            Err(_) => return None,
70        };
71
72        let since_epoch = since_epoch.as_secs();
73
74        Some(since_epoch)
75    };
76
77    loop {
78        if !task.is_alive() {
79            break;
80        }
81
82        // Check to see if the file has been modified. If it has, raise an async event
83        // called "change", and attach the modification timestamp as event data.
84        if let Some(modification) = check_for_modification() {
85            let mut data = DataStore::new();
86            data.add_i64(modification as i64);
87
88            task.raise_async_event("change", data);
89        }
90
91        // Wait for a bit before polling again for any changes to the file.
92        std::thread::sleep(Duration::from_millis(pause_interval_ms));
93    }
94}

Trait Implementations§

Source§

impl Debug for AsyncTaskObject

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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, 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, 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.