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
//! Cairo utilities.
use std::fmt;
pub mod bigint;
pub mod byte_array;
pub mod casts;
pub mod collection_arithmetics;
pub mod extract_matches;
pub mod graph_algos;
pub mod iterators;
#[cfg(feature = "env_logger")]
pub mod logging;
pub mod ordered_hash_map;
pub mod ordered_hash_set;
pub mod unordered_hash_map;
pub mod unordered_hash_set;
/// Similar to From / TryFrom, but returns an option.
pub trait OptionFrom<T>
where
Self: Sized,
{
fn option_from(other: T) -> Option<Self>;
}
pub fn write_comma_separated<Iter: IntoIterator<Item = V>, V: std::fmt::Display>(
f: &mut fmt::Formatter<'_>,
values: Iter,
) -> fmt::Result {
let mut iter = values.into_iter();
if let Some(value) = iter.next() {
write!(f, "{value}")?;
}
for value in iter {
write!(f, ", {value}")?;
}
Ok(())
}
/// Helper operations on `Option<T>`.
pub trait OptionHelper {
fn on_none<F: FnOnce()>(self, f: F) -> Self;
}
impl<T> OptionHelper for Option<T> {
fn on_none<F: FnOnce()>(self, f: F) -> Self {
if self.is_none() {
f();
}
self
}
}
/// Helper operations on `Option<T>`.
pub trait ResultHelper<E> {
fn on_err<F: FnOnce(&E)>(self, f: F) -> Self;
}
impl<T, E> ResultHelper<E> for Result<T, E> {
fn on_err<F: FnOnce(&E)>(self, f: F) -> Self {
match &self {
Ok(_) => self,
Err(e) => {
f(e);
self
}
}
}
}
/// Borrows a mutable reference as Box for the lifespan of this function. Runs the given closure
/// with the boxed value as a parameter.
/// The closure is expected to return a boxed value, whose changes will be reflected on the mutable
/// reference.
/// Example:
/// ```
/// use cairo_lang_utils::borrow_as_box;
/// let mut x = 5;
/// borrow_as_box(&mut x, |mut x: Box<usize>| {
/// *x += 1;
/// ((), x)
/// });
/// assert_eq!(x, 6);
/// ```
pub fn borrow_as_box<T: Default, R, F: FnOnce(Box<T>) -> (R, Box<T>)>(ptr: &mut T, f: F) -> R {
// TODO(spapini): Consider replacing take with something the leaves the memory dangling, instead
// of filling with default().
let (res, boxed) = f(Box::new(std::mem::take(ptr)));
*ptr = *boxed;
res
}
// Defines a short id struct for use with salsa interning.
// Interning is the process of representing a value as an id in a table.
// We usually denote the value type as "long id", and the id type as "short id" or just "id".
// Example:
// A function's long id may be the module in which it is defined and its name. The function is
// assigned a sequential integer (salsa::InternId) which will be its short id. Salsa will hold a
// table to translate between the two representations. Note that a long id of an entity will
// usually include the short id of the entity's parent.
#[macro_export]
macro_rules! define_short_id {
($short_id:ident, $long_id:path, $db:ident, $lookup:ident) => {
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct $short_id(salsa::InternId);
impl salsa::InternKey for $short_id {
fn from_intern_id(salsa_id: salsa::InternId) -> Self {
Self(salsa_id)
}
fn as_intern_id(&self) -> salsa::InternId {
self.0
}
}
// Impl transparent DebugWithDb.
impl<T: ?Sized + cairo_lang_utils::Upcast<dyn $db + 'static>>
cairo_lang_debug::DebugWithDb<T> for $short_id
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &T) -> std::fmt::Result {
use std::fmt::Debug;
use cairo_lang_debug::helper::Fallback;
let db = db.upcast();
cairo_lang_debug::helper::HelperDebug::<$long_id, dyn $db>::helper_debug(
&db.$lookup(*self),
db,
)
.fmt(f)
}
}
};
}
pub trait Upcast<T: ?Sized> {
fn upcast(&self) -> &T;
}
impl<T: ?Sized> Upcast<T> for T {
fn upcast(&self) -> &T {
self
}
}
pub trait UpcastMut<T: ?Sized> {
fn upcast_mut(&mut self) -> &mut T;
}
impl<T: ?Sized> UpcastMut<T> for T {
fn upcast_mut(&mut self) -> &mut T {
self
}
}