litrs/
lib.rs

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
115extern crate proc_macro;
116
117#[cfg(test)]
118#[macro_use]
119mod test_util;
120
121#[cfg(test)]
122mod tests;
123
124mod bool;
125mod byte;
126mod bytestr;
127mod char;
128mod err;
129mod escape;
130mod float;
131mod impls;
132mod integer;
133mod parse;
134mod string;
135
136
137use std::{borrow::{Borrow, Cow}, fmt, ops::{Deref, Range}};
138
139pub 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.
156pub type OwnedLiteral = Literal<String>;
157
158/// A literal whose underlying buffer is borrowed.
159pub 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)]
172pub 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
182impl Literal<&str> {
183    /// Makes a copy of the underlying buffer and returns the owned version of
184    /// `Self`.
185    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
198impl<B: Buffer> fmt::Display for Literal<B> {
199    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`.
223pub 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)]
228    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)]
234    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)]
239    fn cut(self, range: Range<usize>) -> Self;
240}
241
242mod sealed {
243    pub trait Sealed {}
244}
245
246impl<'a> sealed::Sealed for &'a str {}
247impl<'a> Buffer for &'a str {
248    #[doc(hidden)]
249    fn cut(self, range: Range<usize>) -> Self {
250        &self[range]
251    }
252
253    type Cow = Cow<'a, str>;
254    #[doc(hidden)]
255    fn into_cow(self) -> Self::Cow {
256        self.into()
257    }
258    type ByteCow = Cow<'a, [u8]>;
259    #[doc(hidden)]
260    fn into_byte_cow(self) -> Self::ByteCow {
261        self.as_bytes().into()
262    }
263}
264
265impl sealed::Sealed for String {}
266impl Buffer for String {
267    #[doc(hidden)]
268    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)]
279    fn into_cow(self) -> Self::Cow {
280        self.into()
281    }
282
283    type ByteCow = Cow<'static, [u8]>;
284    #[doc(hidden)]
285    fn into_byte_cow(self) -> Self::ByteCow {
286        self.into_bytes().into()
287    }
288}