{"id":4506,"date":"2018-11-29T17:55:03","date_gmt":"2018-11-29T23:55:03","guid":{"rendered":"http:\/\/neosmart.net\/blog\/?p=4506"},"modified":"2018-12-04T12:11:38","modified_gmt":"2018-12-04T18:11:38","slug":"rsevents-manual-and-auto-reset-events-for-rust","status":"publish","type":"post","link":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/","title":{"rendered":"rsevents: manual and auto reset events for rust"},"content":{"rendered":"<p><a href=\"https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo.png\" rel=\"follow\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-thumbnail wp-image-4454 colorbox-4506\" src=\"https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo-150x150.png\" alt=\"\" width=\"150\" height=\"150\" srcset=\"https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo-150x150.png 150w, https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo-600x600.png 600w, https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo-300x300.png 300w, https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo.png 1024w\" sizes=\"auto, (max-width: 150px) 100vw, 150px\" \/><\/a>One of the unique characteristics of Rust (both the language and the community that has evolved around it) is a strong acknowledgement of multithreading, synchronization, and concurrency, as witnessed in the design of the core language (which acknowledges OS concepts of threads with <code>sync<\/code>\u00a0and <code>send<\/code>) and the presence of various structures in the standard library aimed at simplifying development of correct, multithreaded code.<\/p>\n<p><code><a href=\"https:\/\/github.com\/neosmart\/rsevents\">rsevents<\/a><\/code>\u00a0is a new crate that should be immediately familiar to anyone that has done multithreaded programming under Windows: it exposes a synchronization <em>primitive<\/em>, namely, an <code>event<\/code>\u00a0for use where <code>Mutex<\/code>\u00a0&#8211; intended to exclusively marshall access to a variable or region of code &#8211; either does not convey the correct semantics or is not the right tool for the job. For those that didn&#8217;t come fleeing to rust from a Win32 background, in Windows an <code>event<\/code>\u00a0is the lowest-level kernel synchronization primitive, which can be thought of as a &#8220;waitable <code>bool<\/code>&#8221; &#8211; it is either <code>set<\/code>\u00a0or <code>reset<\/code>\u00a0(on or off, true or false) and if it isn&#8217;t set, you can wait on it until it becomes set.<\/p>\n<p><!--more--><\/p>\n<p>An event is used for (unstructured) synchronization of state, a lot like an anonymous, 1-bit\u00a0<code>Channel<\/code>\u00a0but simultaneously much more flexible (but trickier!) as it is a primitive. To naively implement events in rust (<a href=\"https:\/\/neosmart.net\/blog\/2015\/pevents-a-cross-platform-win32-events-library\/\" rel=\"follow\">or in posix<\/a>), it would be the equivalent of a conditional variable and a mutex, where the mutex is used only to protect the integrity of the conditional variable (and not to otherwise indicate a critical section), only without spurious wakes. Win32 events (and <code>rsevents<\/code>) come in two different variants, a so-called &#8220;manual reset&#8221; event and the (undoubtedly more important) &#8220;auto reset&#8221; event. To continue with the posix parallel, the behavior is the difference between using <code>pthread_cond_broadcast<\/code> and <code>pthread_cond_signal<\/code>\u00a0&#8211; it either wakes up all waiting listeners or only one, thereby guaranteeing atomicity.<\/p>\n<p><code>rsevents<\/code>\u00a0implements these as <code><a href=\"https:\/\/docs.rs\/rsevents\/0.2.0\/rsevents\/struct.AutoResetEvent.html\">rsevents::AutoResetEvent<\/a><\/code>\u00a0and <a href=\"https:\/\/docs.rs\/rsevents\/0.2.0\/rsevents\/struct.ManualResetEvent.html\" rel=\"nofollow\"><code>rsevents::ManualResetEvent<\/code><\/a>, both <code>impl<\/code>s of the trait <code><a href=\"https:\/\/docs.rs\/rsevents\/0.2.0\/rsevents\/trait.Awaitable.html\">rsevents::Awaitable<\/a><\/code>, atop of the excellent <code>ParkingLot<\/code>\u00a0crate for the best sleep\/wake performance rust currently has to offer, with minimal overhead to boot. <a href=\"https:\/\/docs.rs\/rsevents\/\" rel=\"nofollow\">As the docs illustrate<\/a>, they are dead-simple to use and allow one to quickly get started with easily polling or awaiting state changes:<\/p>\n<pre><code class=\"language-rust\">\/\/ create a new, initially unset event\r\nlet event = AutoResetEvent::new(State::Unset);\r\n\r\n\/\/ and wrap it in an ARC to allow sharing across thread boundaries\r\nlet event = Arc::new(event);\r\n\r\n\/\/ create a worker thread to complete some task\r\n{\r\n\tlet shared = event.clone();\r\n\tstd::thread::spawn(|| {\r\n\t\t\/\/ perform some task\r\n\t\t...\r\n\t\t\/\/ and signal to ONE waiting thread that the result is ready\r\n\t\tshared.set();\r\n\t});\r\n}\r\n\r\n...\r\n\r\n\/\/ wait for the spawned thread to finish the queued work\r\nevent.wait();\r\n<\/code><\/pre>\n<p><code>rsevents<\/code>\u00a0only represents the core underpinnings of event-based synchronization &#8211; as mentioned repeatedly, these are\u00a0<em>synchronization primitives<\/em> and while they may be useful on their own to communicate changes in (one-bit) state,<sup id=\"rf1-4506\"><a href=\"#fn1-4506\" title=\"or to even implement crude critical sections, if you were mad enough\" rel=\"footnote\">1<\/a><\/sup> they are actually more useful to create <code>Awaitable<\/code>\u00a0objects (hence the separation between the events and the <code>Awaitable<\/code>\u00a0interface). This is where the true power of <code>rsevents<\/code>\u00a0is exposed: it lets you build (or return) objects on top of the events, which become asynchronously awaitable.<sup id=\"rf2-4506\"><a href=\"#fn2-4506\" title=\"Not to be confused with async\/await&nbsp;which does the same but only as part of what is basically an event loop\" rel=\"footnote\">2<\/a><\/sup><\/p>\n<p>To get the ball rolling, a separate crate is also being introducing: <code>rsevents-extra<\/code>\u00a0which contains helpful synchronization objects built atop of <code>rsevents<\/code>\u00a0all of which implement <code>rsevents::Awaitable<\/code>. One example of an object implementing such behavior is <code><a href=\"https:\/\/docs.rs\/rsevents\/0.1.0\/rsevents_extra\/struct.CountdownEvent.html\">CountdownEvent<\/a><\/code>\u00a0which implements an awaitable reverse counter that can be used to wait until\u00a0<em>n<\/em> tasks have finished: you initialize it some value, decrement it (calling <code>CountdownEvent::tick()<\/code>) until it reaches zero, at which point any threads waiting on the object (via <code>CountdownEvent::wait()<\/code>, courtesy of <code>rsevents::Awaitable<\/code>) are awoken:<\/p>\n<pre><code class=\"language-rust\">let countdown = CountdownEvent::new(42);\r\n\r\nthread::scope(|scope| {\r\n    let worker_thread = scope.spawn(|_| {\r\n        println!(\"Worker thread reporting for duty!\");\r\n\r\n        \/\/ block here until all the countdown has elapsed\r\n        countdown.wait();\r\n\r\n        println!(\"Worker thread can now do something because the countdown finished!\");\r\n    });\r\n\r\n    for i in 0..1000 {\r\n        if i % 7 == 3 {\r\n            countdown.tick();\r\n        }\r\n    }\r\n});\r\n\r\n<\/code><\/pre>\n<p>It&#8217;s a pretty silly example that doesn&#8217;t do the crate justice, but countdown events are a great way of performantly waiting for an external event predicated on <em>n<\/em> things taking place, and will outperform other alternatives that involve mutating shared state, while simultaneously abstracting away the process of <em>actually waiting<\/em> on the state to change.<\/p>\n<p>In my days of Win32 C\/C++ programming, I had written an entire library of single-file headers each implementing a different synchronization model and built directly atop of auto or manual reset events. Rust has obviated quite a few of them, but there&#8217;s a lot to be said for the flexibility that events have to offer (and their very favorable performance characteristics). <code>rsevents-extra<\/code>\u00a0is intended to be a community project and <a href=\"https:\/\/github.com\/neosmart\/rsevents-extra\/pulls\" rel=\"nofollow\">is accepting pull requests<\/a> for other useful synchronization objects implementing <code>Awaitable<\/code>, so if you have any good ideas, we&#8217;re listening!<\/p>\n<hr class=\"footnotes\"><ol class=\"footnotes\"><li id=\"fn1-4506\"><p>or to even implement crude critical sections, if you were mad enough&nbsp;<a href=\"#rf1-4506\" class=\"backlink\" title=\"Jump back to footnote 1 in the text.\">&#8617;<\/a><\/p><\/li><li id=\"fn2-4506\"><p>Not to be confused with <code>async<\/code>\/<code>await<\/code>\u00a0which does the same but only as part of what is basically an event loop&nbsp;<a href=\"#rf2-4506\" class=\"backlink\" title=\"Jump back to footnote 2 in the text.\">&#8617;<\/a><\/p><\/li><\/ol>","protected":false},"excerpt":{"rendered":"<p>One of the unique characteristics of Rust (both the language and the community that has evolved around it) is a strong acknowledgement of multithreading, synchronization, and concurrency, as witnessed in the design of the core language (which acknowledges OS concepts &hellip; <a href=\"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":505,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[989,52,11,993,936],"class_list":["post-4506","post","type-post","status-publish","format-standard","hentry","category-software","tag-crate","tag-open-source","tag-programming","tag-rsevents","tag-rust"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"One of the unique characteristics of Rust (both the language and the community that has evolved around it) is a strong acknowledgement of multithreading, synchronization, and concurrency, as witnessed in the design of the core language (which acknowledges OS concepts of threads with sync and send) and the presence of various structures in the standard library\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Mahmoud Al-Qudsi\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#article\",\"name\":\"rsevents: manual and auto reset events for rust | The NeoSmart Files\",\"headline\":\"rsevents: manual and auto reset events for rust\",\"author\":{\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/author\\\/mqudsi\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/wp-content\\\/uploads\\\/rust-logo.png\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#articleImage\",\"width\":1024,\"height\":1024},\"datePublished\":\"2018-11-29T17:55:03-06:00\",\"dateModified\":\"2018-12-04T12:11:38-06:00\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#webpage\"},\"articleSection\":\"Software, crate, open source, programming, rsevents, rust\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/category\\\/software\\\/#listItem\",\"name\":\"Software\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/category\\\/software\\\/#listItem\",\"position\":2,\"name\":\"Software\",\"item\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/category\\\/software\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#listItem\",\"name\":\"rsevents: manual and auto reset events for rust\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#listItem\",\"position\":3,\"name\":\"rsevents: manual and auto reset events for rust\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/category\\\/software\\\/#listItem\",\"name\":\"Software\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/#organization\",\"name\":\"The NeoSmart Files\",\"description\":\"Recovery software and more\",\"url\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/author\\\/mqudsi\\\/#author\",\"url\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/author\\\/mqudsi\\\/\",\"name\":\"Mahmoud Al-Qudsi\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/c2643dd7c6df61aed49d9f3d917ac6d61cafbbda5f9b1619f50d3b749dca415a?s=96&d=mm&r=pg\",\"width\":96,\"height\":96,\"caption\":\"Mahmoud Al-Qudsi\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#webpage\",\"url\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/\",\"name\":\"rsevents: manual and auto reset events for rust | The NeoSmart Files\",\"description\":\"One of the unique characteristics of Rust (both the language and the community that has evolved around it) is a strong acknowledgement of multithreading, synchronization, and concurrency, as witnessed in the design of the core language (which acknowledges OS concepts of threads with sync and send) and the presence of various structures in the standard library\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/rsevents-manual-and-auto-reset-events-for-rust\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/author\\\/mqudsi\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/author\\\/mqudsi\\\/#author\"},\"datePublished\":\"2018-11-29T17:55:03-06:00\",\"dateModified\":\"2018-12-04T12:11:38-06:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/\",\"name\":\"The NeoSmart Files\",\"description\":\"Recovery software and more\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/neosmart.net\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"rsevents: manual and auto reset events for rust | The NeoSmart Files","description":"One of the unique characteristics of Rust (both the language and the community that has evolved around it) is a strong acknowledgement of multithreading, synchronization, and concurrency, as witnessed in the design of the core language (which acknowledges OS concepts of threads with sync and send) and the presence of various structures in the standard library","canonical_url":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#article","name":"rsevents: manual and auto reset events for rust | The NeoSmart Files","headline":"rsevents: manual and auto reset events for rust","author":{"@id":"https:\/\/neosmart.net\/blog\/author\/mqudsi\/#author"},"publisher":{"@id":"https:\/\/neosmart.net\/blog\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo.png","@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#articleImage","width":1024,"height":1024},"datePublished":"2018-11-29T17:55:03-06:00","dateModified":"2018-12-04T12:11:38-06:00","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#webpage"},"isPartOf":{"@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#webpage"},"articleSection":"Software, crate, open source, programming, rsevents, rust"},{"@type":"BreadcrumbList","@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/neosmart.net\/blog\/#listItem","position":1,"name":"Home","item":"https:\/\/neosmart.net\/blog\/","nextItem":{"@type":"ListItem","@id":"https:\/\/neosmart.net\/blog\/category\/software\/#listItem","name":"Software"}},{"@type":"ListItem","@id":"https:\/\/neosmart.net\/blog\/category\/software\/#listItem","position":2,"name":"Software","item":"https:\/\/neosmart.net\/blog\/category\/software\/","nextItem":{"@type":"ListItem","@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#listItem","name":"rsevents: manual and auto reset events for rust"},"previousItem":{"@type":"ListItem","@id":"https:\/\/neosmart.net\/blog\/#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#listItem","position":3,"name":"rsevents: manual and auto reset events for rust","previousItem":{"@type":"ListItem","@id":"https:\/\/neosmart.net\/blog\/category\/software\/#listItem","name":"Software"}}]},{"@type":"Organization","@id":"https:\/\/neosmart.net\/blog\/#organization","name":"The NeoSmart Files","description":"Recovery software and more","url":"https:\/\/neosmart.net\/blog\/"},{"@type":"Person","@id":"https:\/\/neosmart.net\/blog\/author\/mqudsi\/#author","url":"https:\/\/neosmart.net\/blog\/author\/mqudsi\/","name":"Mahmoud Al-Qudsi","image":{"@type":"ImageObject","@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/c2643dd7c6df61aed49d9f3d917ac6d61cafbbda5f9b1619f50d3b749dca415a?s=96&d=mm&r=pg","width":96,"height":96,"caption":"Mahmoud Al-Qudsi"}},{"@type":"WebPage","@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#webpage","url":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/","name":"rsevents: manual and auto reset events for rust | The NeoSmart Files","description":"One of the unique characteristics of Rust (both the language and the community that has evolved around it) is a strong acknowledgement of multithreading, synchronization, and concurrency, as witnessed in the design of the core language (which acknowledges OS concepts of threads with sync and send) and the presence of various structures in the standard library","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/neosmart.net\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/#breadcrumblist"},"author":{"@id":"https:\/\/neosmart.net\/blog\/author\/mqudsi\/#author"},"creator":{"@id":"https:\/\/neosmart.net\/blog\/author\/mqudsi\/#author"},"datePublished":"2018-11-29T17:55:03-06:00","dateModified":"2018-12-04T12:11:38-06:00"},{"@type":"WebSite","@id":"https:\/\/neosmart.net\/blog\/#website","url":"https:\/\/neosmart.net\/blog\/","name":"The NeoSmart Files","description":"Recovery software and more","inLanguage":"en-US","publisher":{"@id":"https:\/\/neosmart.net\/blog\/#organization"}}]}},"aioseo_meta_data":{"post_id":"4506","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[],"defaultGraph":"","defaultPostTypeGraph":""},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"location":null,"local_seo":null,"breadcrumb_settings":null,"limit_modified_date":false,"ai":null,"created":"2020-12-23 20:00:10","updated":"2026-01-10 22:17:44","focus_keyword":null,"additional_keywords":null,"truseo_locale":null,"seo_analyzer_scan_date":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/neosmart.net\/blog\/\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/neosmart.net\/blog\/category\/software\/\" title=\"Software\">Software<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\trsevents: manual and auto reset events for rust\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/neosmart.net\/blog\/"},{"label":"Software","link":"https:\/\/neosmart.net\/blog\/category\/software\/"},{"label":"rsevents: manual and auto reset events for rust","link":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/"}],"jetpack_shortlink":"https:\/\/wp.me\/p4xDa-1aG","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/posts\/4506","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/users\/505"}],"replies":[{"embeddable":true,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/comments?post=4506"}],"version-history":[{"count":8,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/posts\/4506\/revisions"}],"predecessor-version":[{"id":4514,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/posts\/4506\/revisions\/4514"}],"wp:attachment":[{"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/media?parent=4506"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/categories?post=4506"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/tags?post=4506"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}