@@ -31,6 +31,10 @@ pub enum MathFunction<V> {
3131 Clamp ( Calc < V > , Calc < V > , Calc < V > ) ,
3232 /// The [`round()`](https://www.w3.org/TR/css-values-4/#funcdef-round) function.
3333 Round ( RoundingStrategy , Calc < V > , Calc < V > ) ,
34+ /// The [`rem()`](https://www.w3.org/TR/css-values-4/#funcdef-rem) function.
35+ Rem ( Calc < V > , Calc < V > ) ,
36+ /// The [`mod()`](https://www.w3.org/TR/css-values-4/#funcdef-mod) function.
37+ Mod ( Calc < V > , Calc < V > ) ,
3438}
3539
3640enum_property ! {
@@ -72,6 +76,18 @@ impl<T: Round> TryRound for T {
7276 }
7377}
7478
79+ /// A trait for values that potentially support a remainder (e.g. if they have the same unit).
80+ pub trait TryRem : Sized {
81+ /// Returns the remainder between two values, if possible.
82+ fn try_rem ( & self , rhs : & Self ) -> Option < Self > ;
83+ }
84+
85+ impl < T : std:: ops:: Rem < T , Output = T > + Clone > TryRem for T {
86+ fn try_rem ( & self , rhs : & Self ) -> Option < Self > {
87+ Some ( self . clone ( ) % rhs. clone ( ) )
88+ }
89+ }
90+
7591impl < V : ToCss + std:: cmp:: PartialOrd < f32 > + std:: ops:: Mul < f32 , Output = V > + Clone + std:: fmt:: Debug > ToCss
7692 for MathFunction < V >
7793{
@@ -146,6 +162,20 @@ impl<V: ToCss + std::cmp::PartialOrd<f32> + std::ops::Mul<f32, Output = V> + Clo
146162 b. to_css ( dest) ?;
147163 dest. write_char ( ')' )
148164 }
165+ MathFunction :: Rem ( a, b) => {
166+ dest. write_str ( "rem(" ) ?;
167+ a. to_css ( dest) ?;
168+ dest. delim ( ',' , false ) ?;
169+ b. to_css ( dest) ?;
170+ dest. write_char ( ')' )
171+ }
172+ MathFunction :: Mod ( a, b) => {
173+ dest. write_str ( "mod(" ) ?;
174+ a. to_css ( dest) ?;
175+ dest. delim ( ',' , false ) ?;
176+ b. to_css ( dest) ?;
177+ dest. write_char ( ')' )
178+ }
149179 }
150180 }
151181}
@@ -179,9 +209,11 @@ impl<
179209 + std:: ops:: Mul < f32 , Output = V >
180210 + AddInternal
181211 + TryRound
212+ + TryRem
182213 + std:: cmp:: PartialOrd < V >
183214 + std:: convert:: Into < Calc < V > >
184215 + std:: convert:: From < Calc < V > >
216+ + Clone
185217 + std:: fmt:: Debug ,
186218 > Parse < ' i > for Calc < V >
187219{
@@ -289,6 +321,38 @@ impl<
289321 Ok ( Calc :: Function ( Box :: new( MathFunction :: Round ( strategy, a, b) ) ) )
290322 } )
291323 } ,
324+ "rem" => {
325+ input. parse_nested_block( |input| {
326+ let a: Calc <V > = Calc :: parse_sum( input) ?;
327+ input. expect_comma( ) ?;
328+ let b: Calc <V > = Calc :: parse_sum( input) ?;
329+
330+ if let ( Calc :: Value ( a) , Calc :: Value ( b) ) = ( & a, & b) {
331+ if let Some ( rem) = a. try_rem( & * * b) {
332+ return Ok ( Calc :: Value ( Box :: new( rem) ) )
333+ }
334+ }
335+
336+ Ok ( Calc :: Function ( Box :: new( MathFunction :: Rem ( a, b) ) ) )
337+ } )
338+ } ,
339+ "mod" => {
340+ input. parse_nested_block( |input| {
341+ let a: Calc <V > = Calc :: parse_sum( input) ?;
342+ input. expect_comma( ) ?;
343+ let b: Calc <V > = Calc :: parse_sum( input) ?;
344+
345+ if let ( Calc :: Value ( a) , Calc :: Value ( b) ) = ( & a, & b) {
346+ // ((a % b) + b) % b
347+ if let Some ( rem) = a. try_rem( & * * b) {
348+ let rem = rem. add( ( * * b) . clone( ) ) . try_rem( b) . unwrap( ) ;
349+ return Ok ( Calc :: Value ( Box :: new( rem) ) )
350+ }
351+ }
352+
353+ Ok ( Calc :: Function ( Box :: new( MathFunction :: Rem ( a, b) ) ) )
354+ } )
355+ } ,
292356 _ => Err ( location. new_unexpected_token_error( Token :: Ident ( f. clone( ) ) ) ) ,
293357 }
294358 }
@@ -300,9 +364,11 @@ impl<
300364 + std:: ops:: Mul < f32 , Output = V >
301365 + AddInternal
302366 + TryRound
367+ + TryRem
303368 + std:: cmp:: PartialOrd < V >
304369 + std:: convert:: Into < Calc < V > >
305370 + std:: convert:: From < Calc < V > >
371+ + Clone
306372 + std:: fmt:: Debug ,
307373 > Calc < V >
308374{
0 commit comments