@@ -2,17 +2,18 @@ use crate::session::*;
22use encoding_rs:: mem:: decode_latin1;
33use serde:: { Deserialize , Serialize } ;
44use serde_yaml:: from_str as yaml_from;
5+ use std:: borrow:: Cow ;
56use std:: convert:: TryInto ;
67use std:: default:: Default ;
7- use std:: error:: Error ;
88use std:: ffi:: CStr ;
9- use std:: fmt:: { self , Display } ;
9+ use std:: fmt;
1010use std:: io:: Result as IOResult ;
1111use std:: marker:: PhantomData ;
1212use std:: os:: raw:: { c_char, c_void} ;
1313use std:: os:: windows:: raw:: HANDLE ;
1414use std:: slice:: from_raw_parts;
1515use std:: time:: Duration ;
16+ use thiserror:: Error ;
1617use winapi:: shared:: minwindef:: LPVOID ;
1718use winapi:: um:: errhandlingapi:: GetLastError ;
1819use winapi:: um:: handleapi:: CloseHandle ;
@@ -196,47 +197,47 @@ impl Value {
196197}
197198
198199impl TryInto < i32 > for Value {
199- type Error = & ' static str ;
200+ type Error = ValueError ;
200201
201202 fn try_into ( self ) -> Result < i32 , Self :: Error > {
202203 match self {
203204 Self :: INT ( n) => Ok ( n) ,
204- _ => Err ( "Value is not a signed 4-byte integer" ) ,
205+ _ => Err ( ValueError :: TryInto ( "Value is not a signed 4-byte integer" ) ) ,
205206 }
206207 }
207208}
208209
209210impl TryInto < u32 > for Value {
210- type Error = & ' static str ;
211+ type Error = ValueError ;
211212
212213 fn try_into ( self ) -> Result < u32 , Self :: Error > {
213214 match self {
214215 Self :: INT ( n) => Ok ( n as u32 ) ,
215216 Self :: BITS ( n) => Ok ( n) ,
216- _ => Err ( "Value is not a 4-byte integer" ) ,
217+ _ => Err ( ValueError :: TryInto ( "Value is not a 4-byte integer" ) ) ,
217218 }
218219 }
219220}
220221
221222impl TryInto < f32 > for Value {
222- type Error = & ' static str ;
223+ type Error = ValueError ;
223224
224225 fn try_into ( self ) -> Result < f32 , Self :: Error > {
225226 match self {
226227 Self :: FLOAT ( n) => Ok ( n) ,
227- _ => Err ( "Value is not a float" ) ,
228+ _ => Err ( ValueError :: TryInto ( "Value is not a float" ) ) ,
228229 }
229230 }
230231}
231232
232233impl TryInto < f64 > for Value {
233- type Error = & ' static str ;
234+ type Error = ValueError ;
234235
235236 fn try_into ( self ) -> Result < f64 , Self :: Error > {
236237 match self {
237238 Self :: DOUBLE ( n) => Ok ( n) ,
238239 Self :: FLOAT ( f) => Ok ( f as f64 ) ,
239- _ => Err ( "Value is not a float or double" ) ,
240+ _ => Err ( ValueError :: TryInto ( "Value is not a float or double" ) ) ,
240241 }
241242 }
242243}
@@ -303,7 +304,7 @@ impl Default for ValueHeader {
303304}
304305
305306impl fmt:: Debug for ValueHeader {
306- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> std :: fmt:: Result {
307+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
307308 write ! (
308309 f,
309310 "ValueHeader(name=\" {}\" , type={}, count={}, offset={})" ,
@@ -351,16 +352,12 @@ impl Header {
351352 content
352353 }
353354
354- fn telemetry ( & self , from_loc : * const c_void ) -> Result < Sample , Box < dyn std :: error :: Error > > {
355+ fn telemetry ( & self , from_loc : * const c_void ) -> Sample {
355356 let ( tick, vbh) = self . latest_buffer ( ) ;
356357 let value_buffer = self . var_buffer ( vbh, from_loc) ;
357358 let value_header = self . get_var_header ( from_loc) ;
358359
359- Ok ( Sample :: new (
360- tick,
361- value_header. to_vec ( ) ,
362- value_buffer. to_vec ( ) ,
363- ) )
360+ Sample :: new ( tick, value_header. to_vec ( ) , value_buffer. to_vec ( ) )
364361 }
365362}
366363
@@ -425,9 +422,9 @@ impl Sample {
425422 ///
426423 /// `name` Name of the telemetry variable to get
427424 /// - see the iRacing Telemtry documentation for a complete list of possible values
428- pub fn get ( & self , name : & ' static str ) -> Result < Value , String > {
425+ pub fn get ( & self , name : & ' static str ) -> Result < Value , SampleError > {
429426 match self . header_for ( name) {
430- None => Err ( format ! ( "No value '{}' found" , name) ) ,
427+ None => Err ( SampleError :: NoValue ( format ! ( "No value '{}' found" , name) ) ) ,
431428 Some ( vh) => Ok ( self . value ( & vh) ) ,
432429 }
433430 }
@@ -499,31 +496,51 @@ impl Sample {
499496 }
500497}
501498
502- ///
503- /// Telemetry Error
504- ///
505499/// An error which occurs when telemetry samples cannot be read from the memory buffer.
506- #[ derive( Debug ) ]
500+ #[ derive( Debug , Error ) ]
507501pub enum TelemetryError {
508- ABANDONED ,
509- TIMEOUT ( usize ) ,
510- UNKNOWN ( u32 ) ,
502+ #[ error( "Invalid duration: {0}" ) ]
503+ InvalidDuration ( #[ from] std:: num:: TryFromIntError ) ,
504+
505+ #[ error( "Windows Mutex was abandoned." ) ]
506+ Abandoned ,
507+
508+ #[ error( "Timeout elapsed while waiting for a signal. Duration={0}" ) ]
509+ Timeout ( usize ) ,
510+
511+ #[ error( "Unknown error occurred: {0}" ) ]
512+ Unknown ( u32 ) ,
513+
514+ #[ error( "Wait failed: {0}" ) ]
515+ WaitFailed ( std:: io:: Error ) ,
511516}
512517
513- impl Display for TelemetryError {
514- fn fmt ( & self , f : & mut fmt :: Formatter < ' _ > ) -> fmt :: Result {
515- match self {
516- Self :: ABANDONED => write ! ( f , "Abandoned" ) ,
517- Self :: TIMEOUT ( ms ) => write ! ( f , "Timeout after {}ms" , ms ) ,
518- Self :: UNKNOWN ( v ) => write ! ( f , "Unknown error code = {:x?}" , v ) ,
519- }
520- }
518+ /// An error which occurs while retrieving session info.
519+ # [ derive ( Debug , Error ) ]
520+ pub enum SessionError {
521+ # [ error ( "Text decode error: {0}" ) ]
522+ Decode ( Cow < ' static , str > ) ,
523+
524+ # [ error ( "YAML parse error: {0}" ) ]
525+ ParseYAML ( # [ from ] serde_yaml :: Error ) ,
521526}
522527
523- impl Error for TelemetryError { }
528+ /// An error which occurs when value conversions fail.
529+ #[ derive( Debug , Error ) ]
530+ pub enum ValueError {
531+ #[ error( "{0}" ) ]
532+ TryInto ( & ' static str ) ,
533+ }
534+
535+ /// An error which may occur when reading values from a sample.
536+ #[ derive( Debug , Error ) ]
537+ pub enum SampleError {
538+ #[ error( "{0}" ) ]
539+ NoValue ( String ) ,
540+ }
524541
525542impl < ' conn > Blocking < ' conn > {
526- fn new ( location : * const c_void ) -> std :: io :: Result < Self > {
543+ fn new ( location : * const c_void ) -> IOResult < Self > {
527544 let mut event_name: Vec < u16 > = DATA_EVENT_NAME . encode_utf16 ( ) . collect ( ) ;
528545 event_name. push ( 0 ) ;
529546
@@ -575,29 +592,26 @@ impl<'conn> Blocking<'conn> {
575592 /// # Ok(())
576593 /// # }
577594 /// ```
578- pub fn sample ( & self , timeout : Duration ) -> Result < Sample , Box < dyn Error > > {
579- let wait_time: u32 = match timeout. as_millis ( ) . try_into ( ) {
580- Ok ( v) => v,
581- Err ( e) => return Err ( Box :: new ( e) ) ,
582- } ;
595+ pub fn sample ( & self , timeout : Duration ) -> Result < Sample , TelemetryError > {
596+ let wait_time: u32 = timeout. as_millis ( ) . try_into ( ) ?;
583597
584598 unsafe {
585599 let signal = WaitForSingleObject ( self . event_handle , wait_time) ;
586600
587601 match signal {
588- 0x80 => Err ( Box :: new ( TelemetryError :: ABANDONED ) ) , // Abandoned
589- 0x102 => Err ( Box :: new ( TelemetryError :: TIMEOUT ( wait_time as usize ) ) ) , // Timeout
602+ 0x80 => Err ( TelemetryError :: Abandoned ) ,
603+ 0x102 => Err ( TelemetryError :: Timeout ( wait_time as usize ) ) ,
590604 0xFFFFFFFF => {
591605 // Error
592- let errno = GetLastError ( ) as i32 ;
593- Err ( Box :: new ( std :: io :: Error :: from_raw_os_error ( errno) ) )
606+ let errno = std :: io :: Error :: from_raw_os_error ( GetLastError ( ) as i32 ) ;
607+ Err ( TelemetryError :: WaitFailed ( errno) )
594608 }
595609 0x00 => {
596610 // OK
597611 ResetEvent ( self . event_handle ) ;
598- self . read_header ( ) . telemetry ( self . origin )
612+ Ok ( self . read_header ( ) . telemetry ( self . origin ) )
599613 }
600- _ => Err ( Box :: new ( TelemetryError :: UNKNOWN ( signal as u32 ) ) ) ,
614+ _ => Err ( TelemetryError :: Unknown ( signal as u32 ) ) ,
601615 }
602616 }
603617 }
@@ -688,7 +702,7 @@ impl Connection {
688702 /// Err(e) => println!("Invalid Session")
689703 /// };
690704 /// ```
691- pub fn session_info ( & self ) -> Result < SessionDetails , Box < dyn std :: error :: Error > > {
705+ pub fn session_info ( & self ) -> Result < SessionDetails , SessionError > {
692706 let header = self . read_header ( ) ;
693707
694708 let start = ( self . location as usize + header. session_info_offset as usize ) as * const u8 ;
@@ -711,14 +725,14 @@ impl Connection {
711725 /// # Examples
712726 ///
713727 /// ```
714- /// # fn main() -> Result<(), Box<dyn std::error ::Error> > {
728+ /// # fn main() -> Result<(), std::io ::Error> {
715729 /// use iracing::telemetry::Connection;
716730 ///
717- /// let sample = Connection::new()?.telemetry()? ;
731+ /// let sample = Connection::new()?.telemetry();
718732 /// # Ok(())
719733 /// # }
720734 /// ```
721- pub fn telemetry ( & self ) -> Result < Sample , Box < dyn std :: error :: Error > > {
735+ pub fn telemetry ( & self ) -> Sample {
722736 let header = self . read_header ( ) ;
723737 header. telemetry ( self . location as * const std:: ffi:: c_void )
724738 }
@@ -788,12 +802,6 @@ mod tests {
788802 fn test_latest_telemetry ( ) {
789803 let session_tick: u32 = Connection :: new ( )
790804 . expect ( "Unable to open telemetry" )
791- . telemetry ( )
792- . expect ( "Couldn't get latest telem" )
793- . get ( "SessionTick" )
794- . unwrap ( )
795- . try_into ( )
796- . unwrap ( ) ;
797- assert ! ( session_tick > 0 ) ;
805+ . telemetry ( ) ;
798806 }
799807}
0 commit comments