1use std::{collections::HashSet, num::ParseIntError, str::FromStr};
5
6use futures::future;
7use linera_base::{
8 crypto::CryptoError,
9 data_types::{TimeDelta, Timestamp},
10 identifiers::{ApplicationId, ChainId, GenericApplicationId},
11 time::Duration,
12};
13use linera_core::{data_types::RoundTimeout, node::NotificationStream, worker::Reason};
14use tokio_stream::StreamExt as _;
15
16pub fn parse_millis(s: &str) -> Result<Duration, ParseIntError> {
17 Ok(Duration::from_millis(s.parse()?))
18}
19
20pub fn parse_secs(s: &str) -> Result<Duration, ParseIntError> {
21 Ok(Duration::from_secs(s.parse()?))
22}
23
24pub fn parse_millis_delta(s: &str) -> Result<TimeDelta, ParseIntError> {
25 Ok(TimeDelta::from_millis(s.parse()?))
26}
27
28pub fn parse_chain_set(s: &str) -> Result<HashSet<ChainId>, CryptoError> {
29 match s.trim() {
30 "" => Ok(HashSet::new()),
31 s => s.split(",").map(ChainId::from_str).collect(),
32 }
33}
34
35pub fn parse_app_set(s: &str) -> anyhow::Result<HashSet<GenericApplicationId>> {
36 s.trim()
37 .split(",")
38 .map(|app_str| {
39 GenericApplicationId::from_str(app_str)
40 .or_else(|_| Ok(ApplicationId::from_str(app_str)?.into()))
41 })
42 .collect()
43}
44
45pub fn parse_ascii_alphanumeric_string(s: &str) -> Result<String, &'static str> {
46 if s.chars().all(|x| x.is_ascii_alphanumeric()) {
47 Ok(s.to_string())
48 } else {
49 Err("Expecting ASCII alphanumeric characters")
50 }
51}
52
53pub async fn wait_for_next_round(stream: &mut NotificationStream, timeout: RoundTimeout) {
55 let mut stream = stream.filter(|notification| match ¬ification.reason {
56 Reason::NewBlock { height, .. } | Reason::NewEvents { height, .. } => {
57 *height >= timeout.next_block_height
58 }
59 Reason::NewRound { round, .. } => *round > timeout.current_round,
60 Reason::NewIncomingBundle { .. } | Reason::BlockExecuted { .. } => false,
61 });
62 future::select(
63 Box::pin(stream.next()),
64 Box::pin(linera_base::time::timer::sleep(
65 timeout.timestamp.duration_since(Timestamp::now()),
66 )),
67 )
68 .await;
69}
70
71macro_rules! impl_from_infallible {
72 ($target:path) => {
73 impl From<::std::convert::Infallible> for $target {
74 fn from(infallible: ::std::convert::Infallible) -> Self {
75 match infallible {}
76 }
77 }
78 };
79}
80
81pub(crate) use impl_from_infallible;