/ crates / caret / src / lib.rs
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  }