1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
//! This module provides a common set of types and library functions that are shared
//! between the Linera protocol (compiled from Rust to native code) and Linera
//! applications (compiled from Rust to Wasm).
#![deny(missing_docs)]
#![deny(clippy::large_futures)]
use std::fmt;
#[doc(hidden)]
pub use async_trait::async_trait;
#[cfg(not(target_arch = "wasm32"))]
use {::tracing::debug, tokio::signal::unix, tokio_util::sync::CancellationToken};
pub mod abi;
#[cfg(not(target_arch = "wasm32"))]
pub mod command;
pub mod crypto;
pub mod data_types;
pub mod dyn_convert;
mod graphql;
pub mod hashed;
pub mod http;
pub mod identifiers;
mod limited_writer;
pub mod ownership;
#[cfg(not(target_arch = "wasm32"))]
pub mod port;
#[cfg(with_metrics)]
pub mod prometheus_util;
#[cfg(not(chain))]
pub mod task;
pub mod vm;
#[cfg(not(chain))]
pub use task::Blocking;
pub mod time;
#[cfg_attr(web, path = "tracing_web.rs")]
pub mod tracing;
#[cfg(test)]
mod unit_tests;
pub use graphql::BcsHexParseError;
#[doc(hidden)]
pub use {async_graphql, bcs, hex};
/// A macro for asserting that a condition is true, returning an error if it is not.
///
/// # Examples
///
/// ```
/// # use linera_base::ensure;
/// fn divide(x: i32, y: i32) -> Result<i32, String> {
/// ensure!(y != 0, "division by zero");
/// Ok(x / y)
/// }
///
/// assert_eq!(divide(10, 2), Ok(5));
/// assert_eq!(divide(10, 0), Err(String::from("division by zero")));
/// ```
#[macro_export]
macro_rules! ensure {
($cond:expr, $e:expr) => {
if !($cond) {
return Err($e.into());
}
};
}
/// Formats a byte sequence as a hexadecimal string, and elides bytes in the middle if it is longer
/// than 32 bytes.
///
/// This function is intended to be used with the `#[debug(with = "hex_debug")]` field
/// annotation of `custom_debug_derive::Debug`.
///
/// # Examples
///
/// ```
/// # use linera_base::hex_debug;
/// use custom_debug_derive::Debug;
///
/// #[derive(Debug)]
/// struct Message {
/// #[debug(with = "hex_debug")]
/// bytes: Vec<u8>,
/// }
///
/// let msg = Message {
/// bytes: vec![0x12, 0x34, 0x56, 0x78],
/// };
///
/// assert_eq!(format!("{:?}", msg), "Message { bytes: 12345678 }");
///
/// let long_msg = Message {
/// bytes: b" 10 20 30 40 50".to_vec(),
/// };
///
/// assert_eq!(
/// format!("{:?}", long_msg),
/// "Message { bytes: 20202020202020203130202020202020..20202020343020202020202020203530 }"
/// );
/// ```
pub fn hex_debug<T: AsRef<[u8]>>(bytes: &T, f: &mut fmt::Formatter) -> fmt::Result {
const ELIDE_AFTER: usize = 16;
let bytes = bytes.as_ref();
if bytes.len() <= 2 * ELIDE_AFTER {
write!(f, "{}", hex::encode(bytes))?;
} else {
write!(
f,
"{}..{}",
hex::encode(&bytes[..ELIDE_AFTER]),
hex::encode(&bytes[(bytes.len() - ELIDE_AFTER)..])
)?;
}
Ok(())
}
/// Applies `hex_debug` to a slice of byte vectors.
///
/// # Examples
///
/// ```
/// # use linera_base::hex_vec_debug;
/// use custom_debug_derive::Debug;
///
/// #[derive(Debug)]
/// struct Messages {
/// #[debug(with = "hex_vec_debug")]
/// byte_vecs: Vec<Vec<u8>>,
/// }
///
/// let msgs = Messages {
/// byte_vecs: vec![vec![0x12, 0x34, 0x56, 0x78], vec![0x9A]],
/// };
///
/// assert_eq!(
/// format!("{:?}", msgs),
/// "Messages { byte_vecs: [12345678, 9a] }"
/// );
/// ```
#[allow(clippy::ptr_arg)] // This only works with custom_debug_derive if it's &Vec.
pub fn hex_vec_debug(list: &Vec<Vec<u8>>, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[")?;
for (i, bytes) in list.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
hex_debug(bytes, f)?;
}
write!(f, "]")
}
/// Listens for shutdown signals, and notifies the [`CancellationToken`] if one is
/// received.
#[cfg(not(target_arch = "wasm32"))]
pub async fn listen_for_shutdown_signals(shutdown_sender: CancellationToken) {
let _shutdown_guard = shutdown_sender.drop_guard();
let mut sigint =
unix::signal(unix::SignalKind::interrupt()).expect("Failed to set up SIGINT handler");
let mut sigterm =
unix::signal(unix::SignalKind::terminate()).expect("Failed to set up SIGTERM handler");
let mut sighup =
unix::signal(unix::SignalKind::hangup()).expect("Failed to set up SIGHUP handler");
tokio::select! {
_ = sigint.recv() => debug!("Received SIGINT"),
_ = sigterm.recv() => debug!("Received SIGTERM"),
_ = sighup.recv() => debug!("Received SIGHUP"),
}
}