1 //! Parsing and inspecting Rust literal tokens. 2 //! 3 //! This library offers functionality to parse Rust literals, i.e. tokens in the 4 //! Rust programming language that represent fixed values. The grammar for 5 //! those is defined [here][ref]. 6 //! 7 //! This kind of functionality already exists in the crate `syn`. However, as 8 //! you oftentimes don't need (nor want) the full power of `syn`, `litrs` was 9 //! built. This crate also offers a bit more flexibility compared to `syn` 10 //! (only regarding literals, of course). 11 //! 12 //! --- 13 //! 14 //! The main types of this library are [`Literal`], representing any kind of 15 //! literal, and `*Lit`, like [`StringLit`] or [`FloatLit`], representing a 16 //! specific kind of literal. 17 //! 18 //! There are different ways to obtain such a literal type: 19 //! 20 //! - **`parse`**: parses a `&str` or `String` and returns `Result<_, 21 //! ParseError>`. For example: [`Literal::parse`] and 22 //! [`IntegerLit::parse`]. 23 //! 24 //! - **`From<proc_macro::Literal> for Literal`**: turns a `Literal` value from 25 //! the `proc_macro` crate into a `Literal` from this crate. 26 //! 27 //! - **`TryFrom<proc_macro::Literal> for *Lit`**: tries to turn a 28 //! `proc_macro::Literal` into a specific literal type of this crate. If 29 //! the input is a literal of a different kind, `Err(InvalidToken)` is 30 //! returned. 31 //! 32 //! - **`TryFrom<proc_macro::TokenTree>`**: attempts to turn a token tree into a 33 //! literal type of this crate. An error is returned if the token tree is 34 //! not a literal, or if you are trying to turn it into a specific kind of 35 //! literal and the token tree is a different kind of literal. 36 //! 37 //! All of the `From` and `TryFrom` conversions also work for reference to 38 //! `proc_macro` types. Additionally, if the crate feature `proc-macro2` is 39 //! enabled (which it is by default), all these `From` and `TryFrom` impls also 40 //! exist for the corresponding `proc_macro2` types. 41 //! 42 //! **Note**: `true` and `false` are `Ident`s when passed to your proc macro. 43 //! The `TryFrom<TokenTree>` impls check for those two special idents and 44 //! return a `BoolLit` appropriately. For that reason, there is also no 45 //! `TryFrom<proc_macro::Literal>` impl for `BoolLit`. The `proc_macro::Literal` 46 //! simply cannot represent bool literals. 47 //! 48 //! 49 //! # Examples 50 //! 51 //! In a proc-macro: 52 //! 53 //! ```ignore 54 //! use std::convert::TryFrom; 55 //! use proc_macro::TokenStream; 56 //! use litrs::FloatLit; 57 //! 58 //! #[proc_macro] 59 //! pub fn foo(input: TokenStream) -> TokenStream { 60 //! let mut input = input.into_iter().collect::<Vec<_>>(); 61 //! if input.len() != 1 { 62 //! // Please do proper error handling in your real code! 63 //! panic!("expected exactly one token as input"); 64 //! } 65 //! let token = input.remove(0); 66 //! 67 //! match FloatLit::try_from(token) { 68 //! Ok(float_lit) => { /* do something */ } 69 //! Err(e) => return e.to_compile_error(), 70 //! } 71 //! 72 //! // Dummy output 73 //! TokenStream::new() 74 //! } 75 //! ``` 76 //! 77 //! Parsing from string: 78 //! 79 //! ``` 80 //! use litrs::{FloatLit, Literal}; 81 //! 82 //! // Parse a specific kind of literal (float in this case): 83 //! let float_lit = FloatLit::parse("3.14f32"); 84 //! assert!(float_lit.is_ok()); 85 //! assert_eq!(float_lit.unwrap().type_suffix(), Some(litrs::FloatType::F32)); 86 //! assert!(FloatLit::parse("'c'").is_err()); 87 //! 88 //! // Parse any kind of literal. After parsing, you can inspect the literal 89 //! // and decide what to do in each case. 90 //! let lit = Literal::parse("0xff80").expect("failed to parse literal"); 91 //! match lit { 92 //! Literal::Integer(lit) => { /* ... */ } 93 //! Literal::Float(lit) => { /* ... */ } 94 //! Literal::Bool(lit) => { /* ... */ } 95 //! Literal::Char(lit) => { /* ... */ } 96 //! Literal::String(lit) => { /* ... */ } 97 //! Literal::Byte(lit) => { /* ... */ } 98 //! Literal::ByteString(lit) => { /* ... */ } 99 //! } 100 //! ``` 101 //! 102 //! 103 //! 104 //! # Crate features 105 //! 106 //! - `proc-macro2` (**default**): adds the dependency `proc_macro2`, a bunch of 107 //! `From` and `TryFrom` impls, and [`InvalidToken::to_compile_error2`]. 108 //! 109 //! 110 //! [ref]: https://doc.rust-lang.org/reference/tokens.html#literals 111 //! 112 113 #![deny(missing_debug_implementations)] 114 115 extern crate proc_macro; 116 117 #[cfg(test)] 118 #[macro_use] 119 mod test_util; 120 121 #[cfg(test)] 122 mod tests; 123 124 mod bool; 125 mod byte; 126 mod bytestr; 127 mod char; 128 mod err; 129 mod escape; 130 mod float; 131 mod impls; 132 mod integer; 133 mod parse; 134 mod string; 135 136 137 use std::{borrow::{Borrow, Cow}, fmt, ops::{Deref, Range}}; 138 139 pub use self::{ 140 bool::BoolLit, 141 byte::ByteLit, 142 bytestr::ByteStringLit, 143 char::CharLit, 144 err::{InvalidToken, ParseError}, 145 float::{FloatLit, FloatType}, 146 integer::{FromIntegerLiteral, IntegerLit, IntegerBase, IntegerType}, 147 string::StringLit, 148 }; 149 150 151 // ============================================================================================== 152 // ===== `Literal` and type defs 153 // ============================================================================================== 154 155 /// A literal which owns the underlying buffer. 156 pub type OwnedLiteral = Literal<String>; 157 158 /// A literal whose underlying buffer is borrowed. 159 pub type SharedLiteral<'a> = Literal<&'a str>; 160 161 /// A literal. This is the main type of this library. 162 /// 163 /// This type is generic over the underlying buffer `B`, which can be `&str` or 164 /// `String`. There are two useful type aliases: [`OwnedLiteral`] and 165 /// [`SharedLiteral`]. 166 /// 167 /// To create this type, you have to either call [`Literal::parse`] with an 168 /// input string or use the `From<_>` impls of this type. The impls are only 169 /// available of the corresponding crate features are enabled (they are enabled 170 /// by default). 171 #[derive(Debug, Clone, PartialEq, Eq)] 172 pub enum Literal<B: Buffer> { 173 Bool(BoolLit), 174 Integer(IntegerLit<B>), 175 Float(FloatLit<B>), 176 Char(CharLit<B>), 177 String(StringLit<B>), 178 Byte(ByteLit<B>), 179 ByteString(ByteStringLit<B>), 180 } 181 182 impl Literal<&str> { 183 /// Makes a copy of the underlying buffer and returns the owned version of 184 /// `Self`. into_owned(self) -> OwnedLiteral185 pub fn into_owned(self) -> OwnedLiteral { 186 match self { 187 Literal::Bool(l) => Literal::Bool(l.to_owned()), 188 Literal::Integer(l) => Literal::Integer(l.to_owned()), 189 Literal::Float(l) => Literal::Float(l.to_owned()), 190 Literal::Char(l) => Literal::Char(l.to_owned()), 191 Literal::String(l) => Literal::String(l.into_owned()), 192 Literal::Byte(l) => Literal::Byte(l.to_owned()), 193 Literal::ByteString(l) => Literal::ByteString(l.into_owned()), 194 } 195 } 196 } 197 198 impl<B: Buffer> fmt::Display for Literal<B> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 200 match self { 201 Literal::Bool(l) => l.fmt(f), 202 Literal::Integer(l) => l.fmt(f), 203 Literal::Float(l) => l.fmt(f), 204 Literal::Char(l) => l.fmt(f), 205 Literal::String(l) => l.fmt(f), 206 Literal::Byte(l) => l.fmt(f), 207 Literal::ByteString(l) => l.fmt(f), 208 } 209 } 210 } 211 212 213 // ============================================================================================== 214 // ===== Buffer 215 // ============================================================================================== 216 217 /// A shared or owned string buffer. Implemented for `String` and `&str`. *Implementation detail*. 218 /// 219 /// This is trait is implementation detail of this library, cannot be 220 /// implemented in other crates and is not subject to semantic versioning. 221 /// `litrs` only gurantees that this trait is implemented for `String` and 222 /// `for<'a> &'a str`. 223 pub trait Buffer: sealed::Sealed + Deref<Target = str> { 224 /// This is `Cow<'static, str>` for `String`, and `Cow<'a, str>` for `&'a str`. 225 type Cow: From<String> + AsRef<str> + Borrow<str> + Deref<Target = str>; 226 227 #[doc(hidden)] into_cow(self) -> Self::Cow228 fn into_cow(self) -> Self::Cow; 229 230 /// This is `Cow<'static, [u8]>` for `String`, and `Cow<'a, [u8]>` for `&'a str`. 231 type ByteCow: From<Vec<u8>> + AsRef<[u8]> + Borrow<[u8]> + Deref<Target = [u8]>; 232 233 #[doc(hidden)] into_byte_cow(self) -> Self::ByteCow234 fn into_byte_cow(self) -> Self::ByteCow; 235 236 /// Cuts away some characters at the beginning and some at the end. Given 237 /// range has to be in bounds. 238 #[doc(hidden)] cut(self, range: Range<usize>) -> Self239 fn cut(self, range: Range<usize>) -> Self; 240 } 241 242 mod sealed { 243 pub trait Sealed {} 244 } 245 246 impl<'a> sealed::Sealed for &'a str {} 247 impl<'a> Buffer for &'a str { 248 #[doc(hidden)] cut(self, range: Range<usize>) -> Self249 fn cut(self, range: Range<usize>) -> Self { 250 &self[range] 251 } 252 253 type Cow = Cow<'a, str>; 254 #[doc(hidden)] into_cow(self) -> Self::Cow255 fn into_cow(self) -> Self::Cow { 256 self.into() 257 } 258 type ByteCow = Cow<'a, [u8]>; 259 #[doc(hidden)] into_byte_cow(self) -> Self::ByteCow260 fn into_byte_cow(self) -> Self::ByteCow { 261 self.as_bytes().into() 262 } 263 } 264 265 impl sealed::Sealed for String {} 266 impl Buffer for String { 267 #[doc(hidden)] cut(mut self, range: Range<usize>) -> Self268 fn cut(mut self, range: Range<usize>) -> Self { 269 // This is not the most efficient way, but it works. First we cut the 270 // end, then the beginning. Note that `drain` also removes the range if 271 // the iterator is not consumed. 272 self.truncate(range.end); 273 self.drain(..range.start); 274 self 275 } 276 277 type Cow = Cow<'static, str>; 278 #[doc(hidden)] into_cow(self) -> Self::Cow279 fn into_cow(self) -> Self::Cow { 280 self.into() 281 } 282 283 type ByteCow = Cow<'static, [u8]>; 284 #[doc(hidden)] into_byte_cow(self) -> Self::ByteCow285 fn into_byte_cow(self) -> Self::ByteCow { 286 self.into_bytes().into() 287 } 288 } 289