diff --git a/Cargo.toml b/Cargo.toml index 6336e7c..510f1ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,8 @@ tokio = ["hepmc2-macros/tokio", "dep:tokio"] criterion = "0.5.1" rand = "0.8.4" rand_xoshiro = "0.6.0" -tokio = { version = "1.35.1", features = ["rt", "macros"] } +tokio = { version = "1.35.1", features = ["rt", "macros", "fs"] } +tokio-test = "0.4.3" [[bench]] name = "benchmark" diff --git a/Readme.md b/Readme.md index 70760c0..fa9ba32 100644 --- a/Readme.md +++ b/Readme.md @@ -33,4 +33,48 @@ for event in in_events { writer.finish()?; ``` +## Async API + +By default this crate enables the `sync` feature which exposes a sync API. You +can however switch to using a `tokio`-backed async API by disabling the `sync` +feature and enabling the `tokio` feature. + +Either run the following in the root of your crate: + +```sh +cargo add hepmc2 --no-default-features -F tokio +``` + +or make sure a line like the following is present in your `Cargo.toml`: + +```toml +hepmc2 = { version = "0.6.0", default-features = false, features = ["tokio"] } +``` + +The async API is exactly the same as the sync one but IO operations will return +futures that you will, as usual, need to call `await` on. + +### Example + +```rust +// Read events from `events_in.hepmc2` and write them to `events_out.hepmc2` +use hepmc2::{Reader, Writer}; + +use tokio::io::BufReader; +use tokio::fs::File; + +let input = BufReader::new(File::open("events_in.hepmc2").await?); +let mut in_events = Reader::from(input); + +let output = File::create("events_out.hepmc2").await?; +let mut writer = Writer::try_from(output).await?; + +while let Some(event) = in_events.next().await { + let event = event?; + println!("Current cross section: {}", event.xs); + writer.write(&event).await? +} +writer.finish().await?; +``` + License: GPL-3.0-or-later diff --git a/benches/benchmark.rs b/benches/benchmark.rs index c0e5b96..3d5e271 100644 --- a/benches/benchmark.rs +++ b/benches/benchmark.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "sync")] + use std::convert::{AsRef, From}; use std::default::Default; use std::f64::consts::PI; diff --git a/src/lib.rs b/src/lib.rs index a437aaa..987a1c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,8 @@ //! //! # Example //! -//! ```rust,no_run +#![cfg_attr(feature = "sync", doc = "```no_run")] +#![cfg_attr(not(feature = "sync"), doc = "```ignore")] //! // Read events from `events_in.hepmc2` and write them to `events_out.hepmc2` //! use hepmc2::{Reader, Writer}; //! @@ -31,6 +32,61 @@ //! writer.finish()?; //! # Ok::<(), Box>(()) //! ``` +//! +//! ## Async API +//! +//! By default this crate enables the `sync` feature which exposes a sync API. You +//! can however switch to using a `tokio`-backed async API by disabling the `sync` +//! feature and enabling the `tokio` feature. +//! +//! Either run the following in the root of your crate: +//! +//! ```sh +//! cargo add hepmc2 --no-default-features -F tokio +//! ``` +//! +//! or make sure a line like the following is present in your `Cargo.toml`: +//! +//! ```toml +//! hepmc2 = { version = "0.6.0", default-features = false, features = ["tokio"] } +//! ``` +//! +//! The async API is exactly the same as the sync one but IO operations will return +//! futures that you will, as usual, need to call `await` on. For examples, generate +//! the async API documentation in the root of this project: +//! +//! ```sh +//! cargo doc --open --no-default-features -F tokio +//! ``` +//! +//! ### Example +//! +#![cfg_attr(feature = "sync", doc = "```ignore")] +#![cfg_attr(not(feature = "sync"), doc = "```no_run")] +//! # async fn try_main() -> Result<(), Box> { +//! // Read events from `events_in.hepmc2` and write them to `events_out.hepmc2` +//! use hepmc2::{Reader, Writer}; +//! +//! use tokio::io::BufReader; +//! use tokio::fs::File; +//! +//! let input = BufReader::new(File::open("events_in.hepmc2").await?); +//! let mut in_events = Reader::from(input); +//! +//! let output = File::create("events_out.hepmc2").await?; +//! let mut writer = Writer::try_from(output).await?; +//! +//! while let Some(event) = in_events.next().await { +//! let event = event?; +//! println!("Current cross section: {}", event.xs); +//! writer.write(&event).await? +//! } +//! writer.finish().await?; +//! # Ok(()) +//! # } +//! # tokio_test::block_on(async {try_main().await.unwrap()}) +//! ``` + pub mod event; pub mod reader; pub mod writer; diff --git a/src/writer.rs b/src/writer.rs index 17d2d53..88700bf 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -41,7 +41,8 @@ impl Writer { /// /// # Example /// - /// ```rust + #[cfg_attr(feature = "sync", doc = "```")] + #[cfg_attr(not(feature = "sync"), doc = "```ignore")] /// use hepmc2::writer::Writer; /// /// let mut output = Vec::new(); @@ -50,6 +51,18 @@ impl Writer { /// writer.finish()?; /// # Ok::<(), Box>(()) /// ``` + /// + #[cfg_attr(feature = "sync", doc = "```ignore")] + #[cfg_attr(not(feature = "sync"), doc = "```")] + /// # tokio_test::block_on(async { + /// use hepmc2::writer::Writer; + /// + /// let mut output = Vec::new(); + /// let mut writer = Writer::new(&mut output).await.unwrap(); + /// // always call finish at the end + /// writer.finish().await.unwrap(); + /// # }) + /// ``` #[maybe_async::maybe_async] pub async fn new(stream: T) -> Result { Self::with_header(stream, DEFAULT_HEADER).await @@ -62,7 +75,10 @@ impl Writer { /// /// # Example /// - /// ```rust + /// ## Sync + /// + #[cfg_attr(feature = "sync", doc = "```")] + #[cfg_attr(not(feature = "sync"), doc = "```ignore")] /// use hepmc2::writer::Writer; /// /// let mut output = Vec::new(); @@ -71,6 +87,20 @@ impl Writer { /// writer.finish()?; /// # Ok::<(), Box>(()) /// ``` + /// + /// ## Async + /// + #[cfg_attr(feature = "sync", doc = "```ignore")] + #[cfg_attr(not(feature = "sync"), doc = "```")] + /// # tokio_test::block_on(async { + /// use hepmc2::writer::Writer; + /// + /// let mut output = Vec::new(); + /// let mut writer = Writer::with_header(output, "").await.unwrap(); + /// // always call finish at the end + /// writer.finish().await.unwrap(); + /// # }) + /// ``` #[maybe_async::maybe_async] pub async fn with_header( stream: T, @@ -90,15 +120,32 @@ impl Writer { /// /// # Example /// - /// ```rust + /// ## Sync + /// + #[cfg_attr(feature = "sync", doc = "```")] + #[cfg_attr(not(feature = "sync"), doc = "```ignore")] /// use hepmc2::writer::Writer; - /// + /// /// let mut output = Vec::new(); /// let mut writer = Writer::new(&mut output)?; /// // always call finish at the end /// writer.finish()?; /// # Ok::<(), Box>(()) /// ``` + /// + /// ## Async + /// + #[cfg_attr(feature = "sync", doc = "```ignore")] + #[cfg_attr(not(feature = "sync"), doc = "```")] + /// # tokio_test::block_on(async { + /// use hepmc2::writer::Writer; + /// + /// let mut output = Vec::new(); + /// let mut writer = Writer::new(&mut output).await.unwrap(); + /// // always call finish at the end + /// writer.finish().await.unwrap(); + /// # }) + /// ``` #[maybe_async::maybe_async] pub async fn finish(mut self) -> Result<(), std::io::Error> { self.ref_finish().await @@ -108,10 +155,13 @@ impl Writer { /// /// # Example /// - /// ```rust + /// ## Sync + /// + #[cfg_attr(feature = "sync", doc = "```")] + #[cfg_attr(not(feature = "sync"), doc = "```ignore")] /// use hepmc2::writer::Writer; /// use hepmc2::event::Event; - /// + /// /// let mut output = Vec::new(); /// let mut writer = Writer::new(&mut output)?; /// let event = Event::default(); @@ -120,6 +170,23 @@ impl Writer { /// writer.finish()?; /// # Ok::<(), Box>(()) /// ``` + /// + /// ## Async + /// + #[cfg_attr(feature = "sync", doc = "```ignore")] + #[cfg_attr(not(feature = "sync"), doc = "```")] + /// # tokio_test::block_on(async { + /// use hepmc2::writer::Writer; + /// use hepmc2::event::Event; + /// + /// let mut output = Vec::new(); + /// let mut writer = Writer::new(&mut output).await.unwrap(); + /// let event = Event::default(); + /// writer.write(&event).await.unwrap(); + /// // always call finish at the end + /// writer.finish().await.unwrap(); + /// # }) + /// ``` #[maybe_async::maybe_async] pub async fn write(&mut self, event: &Event) -> Result<(), io::Error> { self.write_event_line(event).await?;