{"id":17396820,"url":"https://github.com/faern/triggered","last_synced_at":"2025-06-17T23:35:47.277Z","repository":{"id":44394091,"uuid":"241477812","full_name":"faern/triggered","owner":"faern","description":"Simple Rust triggers that allows triggering a one time event in another task/thread","archived":false,"fork":false,"pushed_at":"2025-05-12T11:59:01.000Z","size":38,"stargazers_count":22,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-12T12:03:47.294Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/faern.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-02-18T22:06:35.000Z","updated_at":"2025-05-12T11:56:33.000Z","dependencies_parsed_at":"2022-07-15T00:46:09.195Z","dependency_job_id":null,"html_url":"https://github.com/faern/triggered","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/faern/triggered","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faern%2Ftriggered","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faern%2Ftriggered/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faern%2Ftriggered/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faern%2Ftriggered/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/faern","download_url":"https://codeload.github.com/faern/triggered/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faern%2Ftriggered/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259742919,"owners_count":22904631,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-16T13:13:12.673Z","updated_at":"2025-06-17T23:35:42.266Z","avatar_url":"https://github.com/faern.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# triggered\n\nTriggers for one time events between tasks and threads.\n\nThe mechanism consists of two types, the `Trigger` and the `Listener`. They come together\nas a pair. Much like the sender/receiver pair of a channel. The trigger half has a\n`Trigger::trigger` method that will make all tasks/threads waiting on\na listener continue executing.\nThe listener both has a sync `Listener::wait` method, and it also implements\n`Future\u003cOutput = ()\u003e` for async support.\n\nBoth the `Trigger` and `Listener` can be cloned. So any number of trigger instances can\ntrigger any number of waiting listeners. When any one trigger instance belonging to the pair is\ntriggered, all the waiting listeners will be unblocked. Waiting on a listener whose\ntrigger already went off will return instantly. So each trigger/listener pair can only be fired\nonce.\n\nThis crate does not use any `unsafe` code.\n\n## Examples\n\nA trivial example showing the basic usage:\n\n```rust\n#[tokio::main]\nasync fn main() {\n    let (trigger, listener) = triggered::trigger();\n\n    let task = tokio::spawn(async {\n        // Blocks until `trigger.trigger()` below\n        listener.await;\n\n        println!(\"Triggered async task\");\n    });\n\n    // This will make any thread blocked in `Listener::wait()` or async task awaiting the\n    // listener continue execution again.\n    trigger.trigger();\n\n    let _ = task.await;\n}\n```\n\nAn example showing a trigger/listener pair being used to gracefully shut down some async\nserver instances on a Ctrl-C event, where only an immutable `Fn` closure is accepted:\n\n```rust\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Error\u003e {\n    let (shutdown_trigger, shutdown_signal1) = triggered::trigger();\n\n    // A sync `Fn` closure will trigger the trigger when the user hits Ctrl-C\n    ctrlc::set_handler(move || {\n        shutdown_trigger.trigger();\n    }).expect(\"Error setting Ctrl-C handler\");\n\n    // If the server library has support for something like a shutdown signal:\n    let shutdown_signal2 = shutdown_signal1.clone();\n    let server1_task = tokio::spawn(async move {\n        SomeServer::new().serve_with_shutdown_signal(shutdown_signal1).await;\n    });\n\n    // Or just select between the long running future and the signal to abort it\n    tokio::select! {\n        server_result = SomeServer::new().serve() =\u003e {\n            eprintln!(\"Server error: {:?}\", server_result);\n        }\n        _ = shutdown_signal2 =\u003e {}\n    }\n\n    let _ = server1_task.await;\n    Ok(())\n}\n```\n\n## Rust Compatibility\n\nWill work with at least the two latest stable Rust releases. This gives users at least six\nweeks to upgrade their Rust toolchain after a new stable is released.\n\nThe current MSRV can be seen in `travis.yml`. Any change to the MSRV will be considered a\nbreaking change and listed in the [changelog](CHANGELOG.md).\n\n## Comparison with similar primitives\n\n### Channels\n\nThe event triggering primitives in this library is somewhat similar to channels. The main\ndifference and why I developed this library is that\n\nThe listener is somewhat similar to a `futures::channel::oneshot::Receiver\u003c()\u003e`. But it:\n * Is not fallible - Implements `Future\u003cOutput = ()\u003e` instead of\n   `Future\u003cOutput = Result\u003cT, Canceled\u003e\u003e`\n * Implements `Clone` - Any number of listeners can wait for the same event\n * Has a sync [`Listener::wait`] - Both synchronous threads, and asynchronous tasks can wait\n   at the same time.\n\nThe trigger, when compared to a `futures::channel::oneshot::Sender\u003c()\u003e` has the differences\nthat it:\n * Is not fallible - The trigger does not care if there are any listeners left\n * Does not consume itself on send, instead takes `\u0026self` - So can be used\n   in situations where it is not owned or not mutable. For example in `Drop` implementations\n   or callback closures that are limited to `Fn` or `FnMut`.\n\n### `futures::future::Abortable`\n\nOne use case of these triggers is to abort futures when some event happens. See examples above.\nThe differences include:\n * A single handle can abort any number of futures\n * Some futures are not properly cleaned up when just dropped the way `Abortable` does it.\n   These libraries sometimes allows creating their futures with a shutdown signal that triggers\n   a clean abort. Something like `serve_with_shutdown(signal: impl Future\u003cOutput = ()\u003e)`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaern%2Ftriggered","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffaern%2Ftriggered","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaern%2Ftriggered/lists"}