css_lexer/
comment_style.rs

1/// An enum representing the "Style" the [Kind::Comment][crate::Kind::Comment] token represents.
2///
3/// A [Token][crate::Token] with [Kind::Comment][crate::Kind::Comment] will store this data internal to the token.
4/// Using [Token::comment_style()][crate::Token::comment_style()] will return this enum, depending on what characters
5/// make up the beginning of the comment token. By default the [Lexer][crate::Lexer] will only produce multi-line - aka
6/// "Block" - comments, but adding [Feature::SeparateWhitespace][crate::Feature::SingleLineComments] will allow the
7/// [Lexer][crate::Lexer] to produce single line comments too.
8///
9/// A basic [Block][CommentStyle::Block] comment style uses the `/*` leading characters, but sub-styles of the block
10/// style are also computed, for example [BlockStar][CommentStyle::BlockStar] represents a comment using the "double
11/// star" syntax to open the comment, i.e. `/**`. Determing if these comments are using these alternate style can help a
12/// parser (or writer) determine if it should retain these comments or otherwise treat them differently to regular block
13/// comments.
14///
15/// ```
16/// use css_lexer::*;
17/// let mut lexer = Lexer::new("/* Normal Comment */  /** Double Star Comment */");
18/// {
19///     // This token will be collapsed Whitespace.
20///     let token = lexer.advance();
21///     assert_eq!(token, Kind::Comment);
22///     assert_eq!(token, CommentStyle::Block);
23/// }
24/// assert_eq!(lexer.advance(), Kind::Whitespace);
25/// {
26///     // This token will be collapsed Whitespace.
27///     let token = lexer.advance();
28///     assert_eq!(token, Kind::Comment);
29///     assert_eq!(token, CommentStyle::BlockStar);
30/// }
31/// ```
32#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(tag = "kind", content = "value"))]
34pub enum CommentStyle {
35	#[default]
36	/// A basic block comment which uses `/*` as the leading style. The third character may be a whitespace, or may
37	/// include a character that _isn't_ `!`, `#`, `=`, `-`.
38	Block = 0b000,
39	/// A block comment which uses `/**` as the leading style. The two `*`s must be adjacent, so this does not count
40	/// `/* *`.
41	BlockStar = 0b001,
42	/// A block comment which uses `/*!` as the leading style. The `*` and `!` must be adjacent, so this does not count
43	/// `/* !`.
44	BlockBang = 0b010,
45	/// A block comment which uses `/*#` as the leading style. The `*` and `#` must be adjacent, so this does not count
46	/// `/* #`.
47	BlockPound = 0b011,
48	/// A block comment which uses `/*=` or `/*-` as the leading style. The `*` and `-` or `=` must be adjacent, so this
49	/// does not count `/* #`.
50	BlockHeading = 0b100,
51	/// A basic single line  comment which uses `//` as the leading style. The third character may be a whitespace, or
52	/// may include a character that _isn't_ `*`, `!`. The [Lexer][crate::Lexer] can only produce a [Token][crate::Token]
53	/// with this style if [Feature::SingleLineComments][crate::Feature::SingleLineComments] is enabled.
54	Single = 0b101,
55	/// A single line comment which uses `//*` as the leading style. The `*` be adjacent to the `//`, so this does not
56	/// count `// *`. The [Lexer][crate::Lexer] can only produce a [Token][crate::Token] with this style if
57	/// [Feature::SingleLineComments][crate::Feature::SingleLineComments] is enabled.
58	SingleStar = 0b110,
59	/// A single line comment which uses `//!` as the leading style. The `!` be adjacent to the `//`, so this does not
60	/// count `// !`. The [Lexer][crate::Lexer] can only produce a [Token][crate::Token] with this style if
61	/// [Feature::SingleLineComments][crate::Feature::SingleLineComments] is enabled.
62	SingleBang = 0b111,
63}
64
65impl CommentStyle {
66	#[inline]
67	pub fn is_block(&self) -> bool {
68		matches!(self, Self::Block | Self::BlockStar | Self::BlockBang | Self::BlockPound | Self::BlockHeading)
69	}
70
71	#[inline]
72	pub fn is_non_standard(&self) -> bool {
73		matches!(self, Self::Single | Self::SingleStar | Self::SingleBang)
74	}
75
76	#[inline]
77	pub fn retain(&self) -> bool {
78		matches!(self, Self::Single | Self::SingleStar | Self::SingleBang)
79	}
80
81	pub(crate) fn from_bits(bits: u8) -> Option<Self> {
82		match bits {
83			0b000 => Some(Self::Block),
84			0b001 => Some(Self::BlockStar),
85			0b010 => Some(Self::BlockBang),
86			0b011 => Some(Self::BlockPound),
87			0b100 => Some(Self::BlockHeading),
88			0b101 => Some(Self::Single),
89			0b110 => Some(Self::SingleStar),
90			0b111 => Some(Self::SingleBang),
91			_ => None,
92		}
93	}
94}
95
96#[test]
97fn size_test() {
98	assert_eq!(::std::mem::size_of::<CommentStyle>(), 1);
99}
100
101#[test]
102fn test_from_bits() {
103	assert_eq!(CommentStyle::from_bits(CommentStyle::Block as u8), Some(CommentStyle::Block));
104	assert_eq!(CommentStyle::from_bits(CommentStyle::BlockStar as u8), Some(CommentStyle::BlockStar));
105	assert_eq!(CommentStyle::from_bits(CommentStyle::BlockBang as u8), Some(CommentStyle::BlockBang));
106	assert_eq!(CommentStyle::from_bits(CommentStyle::BlockPound as u8), Some(CommentStyle::BlockPound));
107	assert_eq!(CommentStyle::from_bits(CommentStyle::BlockHeading as u8), Some(CommentStyle::BlockHeading));
108	assert_eq!(CommentStyle::from_bits(CommentStyle::Single as u8), Some(CommentStyle::Single));
109	assert_eq!(CommentStyle::from_bits(CommentStyle::SingleStar as u8), Some(CommentStyle::SingleStar));
110	assert_eq!(CommentStyle::from_bits(CommentStyle::SingleBang as u8), Some(CommentStyle::SingleBang));
111}