22
33use super :: measurement:: * ;
44
5+ #[ cfg( feature = "from_str" ) ]
6+ use regex:: Regex ;
7+ #[ cfg( feature = "from_str" ) ]
8+ use std:: str:: FromStr ;
9+
510/// The 'Angle' struct can be used to deal with angles in a common way.
611///
712/// # Example
@@ -98,6 +103,33 @@ impl Measurement for Angle {
98103 }
99104}
100105
106+ #[ cfg( feature = "from_str" ) ]
107+ impl FromStr for Angle {
108+ type Err = std:: num:: ParseFloatError ;
109+
110+ /// Create a new Angle from a string
111+ /// Plain numbers in string are considered to be plain degrees
112+ fn from_str ( val : & str ) -> Result < Self , Self :: Err > {
113+ if val. is_empty ( ) {
114+ return Ok ( Angle :: from_degrees ( 0.0 ) ) ;
115+ }
116+
117+ let re = Regex :: new ( r"(?i)\s*([0-9.]*)\s?(deg|\u{00B0}|rad)\s*$" ) . unwrap ( ) ;
118+ if let Some ( caps) = re. captures ( val) {
119+ let float_val = caps. get ( 1 ) . unwrap ( ) . as_str ( ) ;
120+ return Ok (
121+ match caps. get ( 2 ) . unwrap ( ) . as_str ( ) . to_lowercase ( ) . as_str ( ) {
122+ "deg" | "\u{00B0} " => Angle :: from_degrees ( float_val. parse :: < f64 > ( ) ?) ,
123+ "rad" => Angle :: from_radians ( float_val. parse :: < f64 > ( ) ?) ,
124+ _ => Angle :: from_degrees ( val. parse :: < f64 > ( ) ?) ,
125+ } ,
126+ ) ;
127+ }
128+
129+ Ok ( Angle :: from_degrees ( val. parse :: < f64 > ( ) ?) )
130+ }
131+ }
132+
101133implement_measurement ! { Angle }
102134
103135#[ cfg( test) ]
@@ -115,4 +147,51 @@ mod test {
115147 assert_almost_eq ( r1, 2.0 * PI ) ;
116148 assert_almost_eq ( r2, 180.0 ) ;
117149 }
150+
151+ #[ test]
152+ #[ cfg( feature = "from_str" ) ]
153+ fn angle_from_str ( ) {
154+ let t = Angle :: from_str ( "100 deg" ) ;
155+ assert ! ( t. is_ok( ) ) ;
156+
157+ let o = t. unwrap ( ) . as_degrees ( ) ;
158+ assert_almost_eq ( o, 100.0 ) ;
159+ }
160+
161+ #[ test]
162+ #[ cfg( feature = "from_str" ) ]
163+ fn angle_from_degree_str ( ) {
164+ let t = Angle :: from_str ( "100°" ) ;
165+ assert ! ( t. is_ok( ) ) ;
166+
167+ let o = t. unwrap ( ) . as_degrees ( ) ;
168+ assert_almost_eq ( o, 100.0 ) ;
169+ }
170+
171+ #[ test]
172+ #[ cfg( feature = "from_str" ) ]
173+ fn angle_from_radian_str ( ) {
174+ let t = Angle :: from_str ( "100rad" ) ;
175+ assert ! ( t. is_ok( ) ) ;
176+
177+ let o = t. unwrap ( ) . as_radians ( ) ;
178+ assert_almost_eq ( o, 100.0 ) ;
179+ }
180+
181+ #[ test]
182+ #[ cfg( feature = "from_str" ) ]
183+ fn default_str ( ) {
184+ let t = Angle :: from_str ( "100" ) ;
185+ assert ! ( t. is_ok( ) ) ;
186+
187+ let o = t. unwrap ( ) . as_degrees ( ) ;
188+ assert_almost_eq ( o, 100.0 ) ;
189+ }
190+
191+ #[ test]
192+ #[ cfg( feature = "from_str" ) ]
193+ fn invalid_str ( ) {
194+ let t = Angle :: from_str ( "abcd" ) ;
195+ assert ! ( t. is_err( ) ) ;
196+ }
118197}
0 commit comments