rect.rs (4254B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! Generic types for CSS values that are composed of four sides. 6 7 use crate::derives::*; 8 use crate::parser::{Parse, ParserContext}; 9 use cssparser::Parser; 10 use std::fmt::{self, Write}; 11 use style_traits::{CssWriter, ParseError, ToCss}; 12 13 /// A CSS value made of four components, where its `ToCss` impl will try to 14 /// serialize as few components as possible, like for example in `border-width`. 15 #[derive( 16 Animate, 17 Clone, 18 ComputeSquaredDistance, 19 Copy, 20 Debug, 21 Deserialize, 22 MallocSizeOf, 23 PartialEq, 24 SpecifiedValueInfo, 25 Serialize, 26 ToAnimatedValue, 27 ToAnimatedZero, 28 ToComputedValue, 29 ToResolvedValue, 30 ToShmem, 31 ToTyped, 32 )] 33 #[repr(C)] 34 pub struct Rect<T>(pub T, pub T, pub T, pub T); 35 36 impl<T> Rect<T> { 37 /// Returns a new `Rect<T>` value. 38 pub fn new(first: T, second: T, third: T, fourth: T) -> Self { 39 Rect(first, second, third, fourth) 40 } 41 } 42 43 impl<T> Rect<T> 44 where 45 T: Clone, 46 { 47 /// Returns a rect with all the values equal to `v`. 48 pub fn all(v: T) -> Self { 49 Rect::new(v.clone(), v.clone(), v.clone(), v) 50 } 51 52 /// Parses a new `Rect<T>` value with the given parse function. 53 pub fn parse_with<'i, 't, Parse>( 54 context: &ParserContext, 55 input: &mut Parser<'i, 't>, 56 parse: Parse, 57 ) -> Result<Self, ParseError<'i>> 58 where 59 Parse: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>>, 60 { 61 let first = parse(context, input)?; 62 let second = if let Ok(second) = input.try_parse(|i| parse(context, i)) { 63 second 64 } else { 65 // <first> 66 return Ok(Self::new( 67 first.clone(), 68 first.clone(), 69 first.clone(), 70 first, 71 )); 72 }; 73 let third = if let Ok(third) = input.try_parse(|i| parse(context, i)) { 74 third 75 } else { 76 // <first> <second> 77 return Ok(Self::new(first.clone(), second.clone(), first, second)); 78 }; 79 let fourth = if let Ok(fourth) = input.try_parse(|i| parse(context, i)) { 80 fourth 81 } else { 82 // <first> <second> <third> 83 return Ok(Self::new(first, second.clone(), third, second)); 84 }; 85 // <first> <second> <third> <fourth> 86 Ok(Self::new(first, second, third, fourth)) 87 } 88 89 /// Parses a new `Rect<T>` value which all components must be specified, with the given parse 90 /// function. 91 pub fn parse_all_components_with<'i, 't, Parse>( 92 context: &ParserContext, 93 input: &mut Parser<'i, 't>, 94 parse: Parse, 95 ) -> Result<Self, ParseError<'i>> 96 where 97 Parse: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>>, 98 { 99 let first = parse(context, input)?; 100 let second = parse(context, input)?; 101 let third = parse(context, input)?; 102 let fourth = parse(context, input)?; 103 // <first> <second> <third> <fourth> 104 Ok(Self::new(first, second, third, fourth)) 105 } 106 } 107 108 impl<T> Parse for Rect<T> 109 where 110 T: Clone + Parse, 111 { 112 #[inline] 113 fn parse<'i, 't>( 114 context: &ParserContext, 115 input: &mut Parser<'i, 't>, 116 ) -> Result<Self, ParseError<'i>> { 117 Self::parse_with(context, input, T::parse) 118 } 119 } 120 121 impl<T> ToCss for Rect<T> 122 where 123 T: PartialEq + ToCss, 124 { 125 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result 126 where 127 W: Write, 128 { 129 self.0.to_css(dest)?; 130 let same_vertical = self.0 == self.2; 131 let same_horizontal = self.1 == self.3; 132 if same_vertical && same_horizontal && self.0 == self.1 { 133 return Ok(()); 134 } 135 dest.write_char(' ')?; 136 self.1.to_css(dest)?; 137 if same_vertical && same_horizontal { 138 return Ok(()); 139 } 140 dest.write_char(' ')?; 141 self.2.to_css(dest)?; 142 if same_horizontal { 143 return Ok(()); 144 } 145 dest.write_char(' ')?; 146 self.3.to_css(dest) 147 } 148 }