use super::prelude::*;
use crate::{CalcableValue, LengthPercentage};
#[derive(ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum Position<'a> {
One(PositionOne<'a>),
Two(PositionTwo<'a>),
Four(PositionFour<'a>),
}
impl<'a> Peek<'a> for Position<'a> {
const PEEK_KINDSET: KindSet = PositionOne::PEEK_KINDSET;
#[inline(always)]
fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
where
I: Iterator<Item = Cursor> + Clone,
{
PositionOne::peek(p, c)
}
}
impl<'a> Parse<'a> for Position<'a> {
fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let first = p.parse::<PositionOne>()?;
if !p.peek::<PositionOne>() {
return Ok(Self::One(first));
}
let second_c = p.peek_n(1);
let second = p.parse::<PositionOne>()?;
if !p.peek::<PositionOne>() {
return Ok(Self::Two(PositionTwo::from_two(p, first, second, second_c)?));
}
Ok(Self::Four(PositionFour::from_four(p, first, second, second_c)?))
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct AtPosition<'a> {
#[atom(CssAtomSet::At)]
pub keyword: T![Ident],
pub position: Position<'a>,
}
#[derive(Parse, Peek, ToSpan, SemanticEq, ToCursors, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionOne<'a> {
#[atom(CssAtomSet::Left)]
Left(T![Ident]),
#[atom(CssAtomSet::Right)]
Right(T![Ident]),
#[atom(CssAtomSet::Center)]
Center(T![Ident]),
#[atom(CssAtomSet::Top)]
Top(T![Ident]),
#[atom(CssAtomSet::Bottom)]
Bottom(T![Ident]),
#[atom(CssAtomSet::XStart)]
XStart(T![Ident]),
#[atom(CssAtomSet::XEnd)]
XEnd(T![Ident]),
#[atom(CssAtomSet::YStart)]
YStart(T![Ident]),
#[atom(CssAtomSet::YEnd)]
YEnd(T![Ident]),
#[atom(CssAtomSet::BlockStart)]
BlockStart(T![Ident]),
#[atom(CssAtomSet::BlockEnd)]
BlockEnd(T![Ident]),
#[atom(CssAtomSet::InlineStart)]
InlineStart(T![Ident]),
#[atom(CssAtomSet::InlineEnd)]
InlineEnd(T![Ident]),
#[atom(CssAtomSet::Start)]
Start(T![Ident]),
#[atom(CssAtomSet::End)]
End(T![Ident]),
LengthPercentage(CalcableValue<'a, LengthPercentage>),
}
impl<'a> PositionOne<'a> {
pub(crate) fn to_horizontal(&self) -> Option<PositionHorizontal<'a>> {
match self {
Self::Left(t) => Some(PositionHorizontal::Left(*t)),
Self::Right(t) => Some(PositionHorizontal::Right(*t)),
Self::Center(t) => Some(PositionHorizontal::Center(*t)),
Self::XStart(t) => Some(PositionHorizontal::XStart(*t)),
Self::XEnd(t) => Some(PositionHorizontal::XEnd(*t)),
Self::LengthPercentage(l) => Some(PositionHorizontal::LengthPercentage(l.clone())),
_ => None,
}
}
pub(crate) fn to_vertical(&self) -> Option<PositionVertical<'a>> {
match self {
Self::Top(t) => Some(PositionVertical::Top(*t)),
Self::Bottom(t) => Some(PositionVertical::Bottom(*t)),
Self::Center(t) => Some(PositionVertical::Center(*t)),
Self::YStart(t) => Some(PositionVertical::YStart(*t)),
Self::YEnd(t) => Some(PositionVertical::YEnd(*t)),
Self::LengthPercentage(l) => Some(PositionVertical::LengthPercentage(l.clone())),
_ => None,
}
}
pub(crate) fn to_horizontal_keyword(&self) -> Option<PositionHorizontalKeyword> {
match self {
Self::Left(t) => Some(PositionHorizontalKeyword::Left(*t)),
Self::Right(t) => Some(PositionHorizontalKeyword::Right(*t)),
Self::XStart(t) => Some(PositionHorizontalKeyword::XStart(*t)),
Self::XEnd(t) => Some(PositionHorizontalKeyword::XEnd(*t)),
_ => None,
}
}
pub(crate) fn to_vertical_keyword(&self) -> Option<PositionVerticalKeyword> {
match self {
Self::Top(t) => Some(PositionVerticalKeyword::Top(*t)),
Self::Bottom(t) => Some(PositionVerticalKeyword::Bottom(*t)),
Self::YStart(t) => Some(PositionVerticalKeyword::YStart(*t)),
Self::YEnd(t) => Some(PositionVerticalKeyword::YEnd(*t)),
_ => None,
}
}
pub(crate) fn to_block_axis(&self) -> Option<PositionBlockAxis> {
match self {
Self::BlockStart(t) => Some(PositionBlockAxis::BlockStart(*t)),
Self::BlockEnd(t) => Some(PositionBlockAxis::BlockEnd(*t)),
Self::Center(t) => Some(PositionBlockAxis::Center(*t)),
_ => None,
}
}
pub(crate) fn to_inline_axis(&self) -> Option<PositionInlineAxis> {
match self {
Self::InlineStart(t) => Some(PositionInlineAxis::InlineStart(*t)),
Self::InlineEnd(t) => Some(PositionInlineAxis::InlineEnd(*t)),
Self::Center(t) => Some(PositionInlineAxis::Center(*t)),
_ => None,
}
}
pub(crate) fn to_block_axis_keyword(&self) -> Option<PositionBlockAxisKeyword> {
match self {
Self::BlockStart(t) => Some(PositionBlockAxisKeyword::BlockStart(*t)),
Self::BlockEnd(t) => Some(PositionBlockAxisKeyword::BlockEnd(*t)),
_ => None,
}
}
pub(crate) fn to_inline_axis_keyword(&self) -> Option<PositionInlineAxisKeyword> {
match self {
Self::InlineStart(t) => Some(PositionInlineAxisKeyword::InlineStart(*t)),
Self::InlineEnd(t) => Some(PositionInlineAxisKeyword::InlineEnd(*t)),
_ => None,
}
}
pub(crate) fn to_logical(&self) -> Option<PositionLogical> {
match self {
Self::Start(t) => Some(PositionLogical::Start(*t)),
Self::End(t) => Some(PositionLogical::End(*t)),
_ => None,
}
}
}
#[derive(ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionTwo<'a> {
Physical(PositionHorizontal<'a>, PositionVertical<'a>),
FlowRelative(PositionBlockAxis, PositionInlineAxis),
Logical(PositionLogical, PositionLogical),
}
impl<'a> Peek<'a> for PositionTwo<'a> {
const PEEK_KINDSET: KindSet = PositionOne::PEEK_KINDSET;
#[inline(always)]
fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
where
I: Iterator<Item = Cursor> + Clone,
{
PositionOne::peek(p, c)
}
}
impl<'a> PositionTwo<'a> {
pub(crate) fn from_two<I>(
_p: &mut Parser<'a, I>,
first: PositionOne<'a>,
second: PositionOne<'a>,
second_c: Cursor,
) -> ParserResult<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let h = first.to_horizontal();
let v = second.to_vertical();
if let (Some(h), Some(v)) = (h, v) {
return Ok(Self::Physical(h, v));
}
let v = first.to_vertical();
let h = second.to_horizontal();
if let (Some(v), Some(h)) = (v, h) {
return Ok(Self::Physical(h, v));
}
let block = first.to_block_axis();
let inline = second.to_inline_axis();
if let (Some(block), Some(inline)) = (block, inline) {
return Ok(Self::FlowRelative(block, inline));
}
let inline = first.to_inline_axis();
let block = second.to_block_axis();
if let (Some(inline), Some(block)) = (inline, block) {
return Ok(Self::FlowRelative(block, inline));
}
let a = first.to_logical();
let b = second.to_logical();
if let (Some(a), Some(b)) = (a, b) {
return Ok(Self::Logical(a, b));
}
Err(Diagnostic::new(second_c, Diagnostic::unexpected))?
}
}
#[derive(ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionFour<'a> {
Physical(
PositionHorizontalKeyword,
CalcableValue<'a, LengthPercentage>,
PositionVerticalKeyword,
CalcableValue<'a, LengthPercentage>,
),
FlowRelative(
PositionBlockAxisKeyword,
CalcableValue<'a, LengthPercentage>,
PositionInlineAxisKeyword,
CalcableValue<'a, LengthPercentage>,
),
Logical(PositionLogical, CalcableValue<'a, LengthPercentage>, PositionLogical, CalcableValue<'a, LengthPercentage>),
}
impl<'a> PositionFour<'a> {
pub(crate) fn from_four<I>(
p: &mut Parser<'a, I>,
first: PositionOne<'a>,
second: PositionOne<'a>,
second_c: Cursor,
) -> ParserResult<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let PositionOne::LengthPercentage(lp1) = second else {
return Err(Diagnostic::new(second_c, Diagnostic::unexpected))?;
};
let third_c = p.peek_n(1);
let third = p.parse::<PositionOne>()?;
let fourth = p.parse::<CalcableValue<LengthPercentage>>()?;
if let Some(h_kw) = first.to_horizontal_keyword()
&& let Some(v_kw) = third.to_vertical_keyword()
{
return Ok(Self::Physical(h_kw, lp1, v_kw, fourth));
}
if let Some(v_kw) = first.to_vertical_keyword()
&& let Some(h_kw) = third.to_horizontal_keyword()
{
return Ok(Self::Physical(h_kw, fourth, v_kw, lp1));
}
if let Some(b_kw) = first.to_block_axis_keyword()
&& let Some(i_kw) = third.to_inline_axis_keyword()
{
return Ok(Self::FlowRelative(b_kw, lp1, i_kw, fourth));
}
if let Some(i_kw) = first.to_inline_axis_keyword()
&& let Some(b_kw) = third.to_block_axis_keyword()
{
return Ok(Self::FlowRelative(b_kw, fourth, i_kw, lp1));
}
if let Some(a) = first.to_logical()
&& let Some(b) = third.to_logical()
{
return Ok(Self::Logical(a, lp1, b, fourth));
}
Err(Diagnostic::new(third_c, Diagnostic::unexpected))?
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionHorizontal<'a> {
#[atom(CssAtomSet::Left)]
Left(T![Ident]),
#[atom(CssAtomSet::Right)]
Right(T![Ident]),
#[atom(CssAtomSet::Center)]
Center(T![Ident]),
#[atom(CssAtomSet::XStart)]
XStart(T![Ident]),
#[atom(CssAtomSet::XEnd)]
XEnd(T![Ident]),
LengthPercentage(CalcableValue<'a, LengthPercentage>),
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionVertical<'a> {
#[atom(CssAtomSet::Top)]
Top(T![Ident]),
#[atom(CssAtomSet::Bottom)]
Bottom(T![Ident]),
#[atom(CssAtomSet::Center)]
Center(T![Ident]),
#[atom(CssAtomSet::YStart)]
YStart(T![Ident]),
#[atom(CssAtomSet::YEnd)]
YEnd(T![Ident]),
LengthPercentage(CalcableValue<'a, LengthPercentage>),
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionBlockAxis {
#[atom(CssAtomSet::BlockStart)]
BlockStart(T![Ident]),
#[atom(CssAtomSet::BlockEnd)]
BlockEnd(T![Ident]),
#[atom(CssAtomSet::Center)]
Center(T![Ident]),
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionInlineAxis {
#[atom(CssAtomSet::InlineStart)]
InlineStart(T![Ident]),
#[atom(CssAtomSet::InlineEnd)]
InlineEnd(T![Ident]),
#[atom(CssAtomSet::Center)]
Center(T![Ident]),
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionLogical {
#[atom(CssAtomSet::Start)]
Start(T![Ident]),
#[atom(CssAtomSet::End)]
End(T![Ident]),
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionHorizontalKeyword {
#[atom(CssAtomSet::Left)]
Left(T![Ident]),
#[atom(CssAtomSet::Right)]
Right(T![Ident]),
#[atom(CssAtomSet::XStart)]
XStart(T![Ident]),
#[atom(CssAtomSet::XEnd)]
XEnd(T![Ident]),
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionVerticalKeyword {
#[atom(CssAtomSet::Top)]
Top(T![Ident]),
#[atom(CssAtomSet::Bottom)]
Bottom(T![Ident]),
#[atom(CssAtomSet::YStart)]
YStart(T![Ident]),
#[atom(CssAtomSet::YEnd)]
YEnd(T![Ident]),
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionBlockAxisKeyword {
#[atom(CssAtomSet::BlockStart)]
BlockStart(T![Ident]),
#[atom(CssAtomSet::BlockEnd)]
BlockEnd(T![Ident]),
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum PositionInlineAxisKeyword {
#[atom(CssAtomSet::InlineStart)]
InlineStart(T![Ident]),
#[atom(CssAtomSet::InlineEnd)]
InlineEnd(T![Ident]),
}
#[cfg(test)]
mod tests {
use super::*;
use crate::CssAtomSet;
use css_parse::{assert_parse, assert_parse_error, assert_parse_span};
#[test]
fn size_test() {
assert_eq!(std::mem::size_of::<Position<'_>>(), 88);
}
#[test]
fn test_writes() {
assert_parse!(CssAtomSet::ATOMS, Position, "left", Position::One(PositionOne::Left(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "right", Position::One(PositionOne::Right(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "top", Position::One(PositionOne::Top(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "bottom", Position::One(PositionOne::Bottom(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "center", Position::One(PositionOne::Center(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "x-start", Position::One(PositionOne::XStart(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "x-end", Position::One(PositionOne::XEnd(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "y-start", Position::One(PositionOne::YStart(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "y-end", Position::One(PositionOne::YEnd(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "block-start", Position::One(PositionOne::BlockStart(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "block-end", Position::One(PositionOne::BlockEnd(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "inline-start", Position::One(PositionOne::InlineStart(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "inline-end", Position::One(PositionOne::InlineEnd(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "start", Position::One(PositionOne::Start(_)));
assert_parse!(CssAtomSet::ATOMS, Position, "end", Position::One(PositionOne::End(_)));
assert_parse!(
CssAtomSet::ATOMS,
Position,
"50%",
Position::One(PositionOne::LengthPercentage(CalcableValue::Literal(LengthPercentage::Percent(_))))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"center center",
Position::Two(PositionTwo::Physical(PositionHorizontal::Center(_), PositionVertical::Center(_)))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"center top",
Position::Two(PositionTwo::Physical(PositionHorizontal::Center(_), PositionVertical::Top(_)))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"50% 50%",
Position::Two(PositionTwo::Physical(
PositionHorizontal::LengthPercentage(CalcableValue::Literal(LengthPercentage::Percent(_))),
PositionVertical::LengthPercentage(CalcableValue::Literal(LengthPercentage::Percent(_)))
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"20px 30px",
Position::Two(PositionTwo::Physical(
PositionHorizontal::LengthPercentage(CalcableValue::Literal(_)),
PositionVertical::LengthPercentage(CalcableValue::Literal(_))
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"2% bottom",
Position::Two(PositionTwo::Physical(
PositionHorizontal::LengthPercentage(CalcableValue::Literal(LengthPercentage::Percent(_))),
PositionVertical::Bottom(_)
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"-70% -180%",
Position::Two(PositionTwo::Physical(
PositionHorizontal::LengthPercentage(CalcableValue::Literal(LengthPercentage::Percent(_))),
PositionVertical::LengthPercentage(CalcableValue::Literal(LengthPercentage::Percent(_)))
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"right 8.5%",
Position::Two(PositionTwo::Physical(
PositionHorizontal::Right(_),
PositionVertical::LengthPercentage(CalcableValue::Literal(LengthPercentage::Percent(_)))
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"x-start y-end",
Position::Two(PositionTwo::Physical(PositionHorizontal::XStart(_), PositionVertical::YEnd(_)))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"block-start inline-end",
Position::Two(PositionTwo::FlowRelative(
PositionBlockAxis::BlockStart(_),
PositionInlineAxis::InlineEnd(_)
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"inline-end block-start",
Position::Two(PositionTwo::FlowRelative(
PositionBlockAxis::BlockStart(_),
PositionInlineAxis::InlineEnd(_)
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"start end",
Position::Two(PositionTwo::Logical(PositionLogical::Start(_), PositionLogical::End(_)))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"right -6px bottom 12vmin",
Position::Four(PositionFour::Physical(
PositionHorizontalKeyword::Right(_),
CalcableValue::Literal(LengthPercentage::Length(_)),
PositionVerticalKeyword::Bottom(_),
CalcableValue::Literal(LengthPercentage::Length(_))
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"bottom 12vmin right -6px",
Position::Four(PositionFour::Physical(
PositionHorizontalKeyword::Right(_),
CalcableValue::Literal(LengthPercentage::Length(_)),
PositionVerticalKeyword::Bottom(_),
CalcableValue::Literal(LengthPercentage::Length(_))
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"block-start 10px inline-end 20px",
Position::Four(PositionFour::FlowRelative(
PositionBlockAxisKeyword::BlockStart(_),
CalcableValue::Literal(LengthPercentage::Length(_)),
PositionInlineAxisKeyword::InlineEnd(_),
CalcableValue::Literal(LengthPercentage::Length(_))
))
);
assert_parse!(
CssAtomSet::ATOMS,
Position,
"start 10px end 20px",
Position::Four(PositionFour::Logical(
PositionLogical::Start(_),
CalcableValue::Literal(LengthPercentage::Length(_)),
PositionLogical::End(_),
CalcableValue::Literal(LengthPercentage::Length(_))
))
);
}
#[test]
fn test_substitution() {
assert_parse!(CssAtomSet::ATOMS, Position, "calc(50% + 10px)");
assert_parse!(CssAtomSet::ATOMS, Position, "var(--x)");
assert_parse!(CssAtomSet::ATOMS, Position, "calc(50% + 10px) calc(50% - 10px)");
assert_parse!(CssAtomSet::ATOMS, Position, "left calc(50% + 10px)");
assert_parse!(CssAtomSet::ATOMS, Position, "right var(--x) bottom calc(10px)");
}
#[test]
fn test_errors() {
assert_parse_error!(CssAtomSet::ATOMS, Position, "left left");
assert_parse_error!(CssAtomSet::ATOMS, Position, "bottom top");
assert_parse_error!(CssAtomSet::ATOMS, Position, "10px 15px 20px 15px");
assert_parse_error!(CssAtomSet::ATOMS, Position, "right -6px bottom");
}
#[test]
fn test_spans() {
assert_parse_span!(
CssAtomSet::ATOMS,
Position,
r#"
right var(--foo)
^^^^^^^^^^^^^^^^
"#
);
assert_parse_span!(
CssAtomSet::ATOMS,
Position,
r#"
right -6px bottom 12rem 8px 20%
^^^^^^^^^^^^^^^^^^^^^^^
"#
);
}
}