lib.rs
1 #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] 2 #![doc = include_str!("../README.md")] 3 // @@ begin lint list maintained by maint/add_warning @@ 4 #![allow(renamed_and_removed_lints)] // @@REMOVE_WHEN(ci_arti_stable) 5 #![allow(unknown_lints)] // @@REMOVE_WHEN(ci_arti_nightly) 6 #![warn(missing_docs)] 7 #![warn(noop_method_call)] 8 #![warn(unreachable_pub)] 9 #![warn(clippy::all)] 10 #![deny(clippy::await_holding_lock)] 11 #![deny(clippy::cargo_common_metadata)] 12 #![deny(clippy::cast_lossless)] 13 #![deny(clippy::checked_conversions)] 14 #![warn(clippy::cognitive_complexity)] 15 #![deny(clippy::debug_assert_with_mut_call)] 16 #![deny(clippy::exhaustive_enums)] 17 #![deny(clippy::exhaustive_structs)] 18 #![deny(clippy::expl_impl_clone_on_copy)] 19 #![deny(clippy::fallible_impl_from)] 20 #![deny(clippy::implicit_clone)] 21 #![deny(clippy::large_stack_arrays)] 22 #![warn(clippy::manual_ok_or)] 23 #![deny(clippy::missing_docs_in_private_items)] 24 #![warn(clippy::needless_borrow)] 25 #![warn(clippy::needless_pass_by_value)] 26 #![warn(clippy::option_option)] 27 #![deny(clippy::print_stderr)] 28 #![deny(clippy::print_stdout)] 29 #![warn(clippy::rc_buffer)] 30 #![deny(clippy::ref_option_ref)] 31 #![warn(clippy::semicolon_if_nothing_returned)] 32 #![warn(clippy::trait_duplication_in_bounds)] 33 #![deny(clippy::unchecked_duration_subtraction)] 34 #![deny(clippy::unnecessary_wraps)] 35 #![warn(clippy::unseparated_literal_suffix)] 36 #![deny(clippy::unwrap_used)] 37 #![deny(clippy::mod_module_files)] 38 #![allow(clippy::let_unit_value)] // This can reasonably be done for explicitness 39 #![allow(clippy::uninlined_format_args)] 40 #![allow(clippy::significant_drop_in_scrutinee)] // arti/-/merge_requests/588/#note_2812945 41 #![allow(clippy::result_large_err)] // temporary workaround for arti#587 42 #![allow(clippy::needless_raw_string_hashes)] // complained-about code is fine, often best 43 #![allow(clippy::needless_lifetimes)] // See arti#1765 44 //! <!-- @@ end lint list maintained by maint/add_warning @@ --> 45 46 /// Declare an integer type with some named elements. 47 /// 48 /// This macro declares a struct that wraps an integer 49 /// type, and allows any integer type as a value. Some values of this type 50 /// have names, and others do not, but they are all allowed. 51 /// 52 /// This macro is suitable for protocol implementations that accept 53 /// any integer on the wire, and have definitions for some of those 54 /// integers. For example, Tor cell commands are 8-bit integers, but 55 /// not every u8 is a currently recognized Tor command. 56 /// 57 /// # Examples 58 /// ``` 59 /// use caret::caret_int; 60 /// caret_int! { 61 /// pub struct FruitID(u8) { 62 /// AVOCADO = 7, 63 /// PERSIMMON = 8, 64 /// LONGAN = 99 65 /// } 66 /// } 67 /// 68 /// // Known fruits work the way we would expect... 69 /// let a_num: u8 = FruitID::AVOCADO.into(); 70 /// assert_eq!(a_num, 7); 71 /// let a_fruit: FruitID = 8.into(); 72 /// assert_eq!(a_fruit, FruitID::PERSIMMON); 73 /// assert_eq!(format!("I'd like a {}", FruitID::PERSIMMON), 74 /// "I'd like a PERSIMMON"); 75 /// 76 /// // And we can construct unknown fruits, if we encounter any. 77 /// let weird_fruit: FruitID = 202.into(); 78 /// assert_eq!(format!("I'd like a {}", weird_fruit), 79 /// "I'd like a 202"); 80 /// ``` 81 #[macro_export] 82 macro_rules! caret_int { 83 { 84 $(#[$meta:meta])* 85 $v:vis struct $name:ident ( $numtype:ty ) { 86 $( 87 $(#[$item_meta:meta])* 88 $id:ident = $num:literal 89 ),* 90 $(,)? 91 } 92 } => { 93 #[derive(PartialEq,Eq,Copy,Clone)] 94 $(#[$meta])* 95 $v struct $name($numtype); 96 97 impl From<$name> for $numtype { 98 fn from(val: $name) -> $numtype { val.0 } 99 } 100 impl From<$numtype> for $name { 101 fn from(num: $numtype) -> $name { $name(num) } 102 } 103 impl $name { 104 $( 105 $( #[$item_meta] )* 106 pub const $id: $name = $name($num) ; )* 107 fn to_str(self) -> Option<&'static str> { 108 match self { 109 $( $name::$id => Some(stringify!($id)), )* 110 _ => None, 111 } 112 } 113 /// Return true if this value is one that we recognize. 114 $v fn is_recognized(self) -> bool { 115 match self { 116 $( $name::$id => true, )* 117 _ => false 118 } 119 } 120 /// Try to convert this value from one of the recognized names. 121 $v fn from_name(name: &str) -> Option<Self> { 122 match name { 123 $( stringify!($id) => Some($name::$id), )* 124 _ => None 125 } 126 } 127 /// Return the underlying integer that this value represents. 128 fn get(self) -> $numtype { 129 self.into() 130 } 131 } 132 impl std::fmt::Display for $name { 133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 134 match self.to_str() { 135 Some(s) => write!(f, "{}", s), 136 None => write!(f, "{}", self.0), 137 } 138 } 139 } 140 // `#[educe(Debug)]` could do this for us, but let's not deepen this macrology 141 impl std::fmt::Debug for $name { 142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 143 write!(f, "{}({})", stringify!($name), self) 144 } 145 } 146 }; 147 148 }