linera_client/
util.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{collections::HashSet, num::ParseIntError, str::FromStr};
5
6use futures::future;
7use linera_base::{
8    crypto::CryptoError,
9    data_types::{TimeDelta, Timestamp},
10    identifiers::ChainId,
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_ascii_alphanumeric_string(s: &str) -> Result<String, &'static str> {
36    if s.chars().all(|x| x.is_ascii_alphanumeric()) {
37        Ok(s.to_string())
38    } else {
39        Err("Expecting ASCII alphanumeric characters")
40    }
41}
42
43/// Returns after the specified time or if we receive a notification that a new round has started.
44pub async fn wait_for_next_round(stream: &mut NotificationStream, timeout: RoundTimeout) {
45    let mut stream = stream.filter(|notification| match &notification.reason {
46        Reason::NewBlock { height, .. } => *height >= timeout.next_block_height,
47        Reason::NewRound { round, .. } => *round > timeout.current_round,
48        Reason::NewIncomingBundle { .. } => false,
49    });
50    future::select(
51        Box::pin(stream.next()),
52        Box::pin(linera_base::time::timer::sleep(
53            timeout.timestamp.duration_since(Timestamp::now()),
54        )),
55    )
56    .await;
57}
58
59macro_rules! impl_from_dynamic {
60    ($target:ty : $variant:ident, $source:ty) => {
61        impl From<$source> for $target {
62            fn from(error: $source) -> Self {
63                <$target>::$variant(Box::new(error))
64            }
65        }
66    };
67}
68
69macro_rules! impl_from_infallible {
70    ($target:path) => {
71        impl From<::std::convert::Infallible> for $target {
72            fn from(infallible: ::std::convert::Infallible) -> Self {
73                match infallible {}
74            }
75        }
76    };
77}
78
79pub(crate) use impl_from_dynamic;
80pub(crate) use impl_from_infallible;