diff --git a/src/core.rs b/src/core.rs index dd4ed94..cb71324 100644 --- a/src/core.rs +++ b/src/core.rs @@ -259,6 +259,8 @@ pub fn clearerr() { #[derive(Clone, Debug)] pub enum Event { + /// An event type not known to this version of vlc-rs. + Unknown(EventType), MediaMetaChanged(Meta), MediaSubItemAdded, MediaDurationChanged(i64), @@ -325,7 +327,7 @@ pub struct EventManager<'a> { impl<'a> EventManager<'a> { pub fn detach(&self, event_type: EventType, registered_callback: *mut c_void) { - unsafe { sys::libvlc_event_detach(self.ptr, event_type as i32, Some(event_manager_callback), registered_callback) } + unsafe { sys::libvlc_event_detach(self.ptr, event_type.raw() as i32, Some(event_manager_callback), registered_callback) } } pub fn attach(&self, event_type: EventType, callback: F) -> Result<*mut c_void, ()> @@ -339,7 +341,7 @@ impl<'a> EventManager<'a> { let result = unsafe{ sys::libvlc_event_attach( - self.ptr, event_type as i32, Some(event_manager_callback), + self.ptr, event_type.raw() as i32, Some(event_manager_callback), raw) }; @@ -362,7 +364,9 @@ unsafe extern "C" fn event_manager_callback(pe: *const sys::libvlc_event_t, data f(conv_event(pe), VLCObject{ ptr: (*pe).p_obj }); } -// Convert c-style libvlc_event_t to Event +// Convert c-style libvlc_event_t to Event. +// Unknown event types are preserved instead of panicking so newer LibVLC +// releases remain safe to use with this crate. fn conv_event(pe: *const sys::libvlc_event_t) -> Event { let event_type: EventType = (unsafe{ (*pe).type_ } as u32).into(); @@ -390,7 +394,7 @@ fn conv_event(pe: *const sys::libvlc_event_t) -> Event { }, EventType::MediaStateChanged => { unsafe{ - let new_state: sys::libvlc_state_t = (*pe).u.media_state_changed.new_state.try_into().unwrap(); + let new_state = (*pe).u.media_state_changed.new_state as sys::libvlc_state_t; Event::MediaStateChanged(new_state.into()) } }, @@ -555,6 +559,27 @@ fn conv_event(pe: *const sys::libvlc_event_t) -> Event { Event::VlmMediaInstanceStatusError(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name)) } }, + EventType::Unknown(_) => Event::Unknown(event_type), + } +} + +#[cfg(test)] +mod tests { + use super::{conv_event, Event, EventType, sys}; + use std::ptr; + + #[test] + fn conv_event_preserves_an_unknown_event_type() { + let event = sys::libvlc_event_t { + type_: 9999, + p_obj: ptr::null_mut(), + u: unsafe { std::mem::zeroed() }, + }; + + match conv_event(&event) { + Event::Unknown(EventType::Unknown(9999)) => (), + other => panic!("expected unknown event, got {:?}", other), + } } } @@ -579,4 +604,3 @@ impl Log { self.ptr } } - diff --git a/src/enums.rs b/src/enums.rs index 2b90e38..01d5a4c 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -6,12 +6,29 @@ use vlc_sys as sys; macro_rules! define_enum { ($enum_name:ident, $original_type:ident; $($value:ident = $c_value:ident,)*) => { + /// A LibVLC enumeration value. + /// + /// Values added by a newer LibVLC release are represented by `Unknown` + /// rather than causing a panic. Use `raw()` when passing a value back to + /// LibVLC; this replaces casting the enum with `as`. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] - #[repr(C)] pub enum $enum_name { $( - $value = sys::$c_value as isize, + $value, )* + Unknown(sys::$original_type), + } + + impl $enum_name { + /// Returns the raw LibVLC value. + pub fn raw(self) -> sys::$original_type { + match self { + $( + Self::$value => sys::$c_value, + )* + Self::Unknown(value) => value, + } + } } impl From for $enum_name { @@ -20,7 +37,7 @@ macro_rules! define_enum { $( sys::$c_value => Self::$value, )* - _ => unreachable!(), + _ => Self::Unknown(a), } } } @@ -170,3 +187,36 @@ define_enum!( VlmMediaInstanceStatusEnd = libvlc_event_e_libvlc_VlmMediaInstanceStatusEnd, VlmMediaInstanceStatusError = libvlc_event_e_libvlc_VlmMediaInstanceStatusError, ); + +#[cfg(test)] +mod tests { + use super::{EventType, LogLevel, TrackType}; + use vlc_sys as sys; + + #[test] + fn converts_known_raw_values_to_named_variants() { + assert_eq!( + LogLevel::from(sys::libvlc_log_level_LIBVLC_NOTICE), + LogLevel::Dotice, + ); + assert_eq!( + TrackType::from(sys::libvlc_track_type_t_libvlc_track_video), + TrackType::Video, + ); + assert_eq!( + EventType::from(sys::libvlc_event_e_libvlc_MediaPlayerPlaying), + EventType::MediaPlayerPlaying, + ); + } + + #[test] + fn preserves_unknown_raw_values() { + assert_eq!(LogLevel::from(u32::MAX), LogLevel::Unknown(u32::MAX)); + assert_eq!(TrackType::from(-42), TrackType::Unknown(-42)); + assert_eq!( + EventType::from(u32::MAX), + EventType::Unknown(u32::MAX), + ); + assert_eq!(EventType::Unknown(u32::MAX).raw(), u32::MAX); + } +} diff --git a/src/media.rs b/src/media.rs index eaa5d17..293860f 100644 --- a/src/media.rs +++ b/src/media.rs @@ -78,7 +78,7 @@ impl Media { /// If the media has not yet been parsed this will return None. pub fn get_meta(&self, meta: Meta) -> Option { unsafe{ - let p_str = sys::libvlc_media_get_meta(self.ptr, meta as u32); + let p_str = sys::libvlc_media_get_meta(self.ptr, meta.raw()); let s = from_cstr(p_str); sys::libvlc_free(p_str as *mut ::libc::c_void); s @@ -89,7 +89,7 @@ impl Media { /// (This function will not save the meta, call save_meta in order to save the meta) pub fn set_meta(&self, meta: Meta, value: &str) { unsafe{ - sys::libvlc_media_set_meta(self.ptr, meta as u32, to_cstr(value).as_ptr()); + sys::libvlc_media_set_meta(self.ptr, meta.raw(), to_cstr(value).as_ptr()); } } @@ -236,4 +236,3 @@ pub struct VideoTrack { pub struct SubtitleTrack { pub encoding: Option, } - diff --git a/src/media_player.rs b/src/media_player.rs index ee38b4c..760e622 100644 --- a/src/media_player.rs +++ b/src/media_player.rs @@ -311,7 +311,7 @@ impl MediaPlayer { /// Set if, and how, the video title will be shown when media is played. pub fn set_video_title_display(&self, position: Position, timeout: u32) { - unsafe{ sys::libvlc_media_player_set_video_title_display(self.ptr, position as i32, timeout); } + unsafe{ sys::libvlc_media_player_set_video_title_display(self.ptr, position.raw(), timeout); } } /// Returns raw pointer @@ -367,4 +367,3 @@ pub struct TrackDescription { pub id: i32, pub name: Option, } - diff --git a/src/video.rs b/src/video.rs index e9ca4fc..1128513 100644 --- a/src/video.rs +++ b/src/video.rs @@ -110,15 +110,15 @@ impl MediaPlayerVideoEx for MediaPlayer { } } fn get_adjust_int(&self, option: VideoAdjustOption) -> i32 { - unsafe{ sys::libvlc_video_get_adjust_int(self.ptr, option as u32) } + unsafe{ sys::libvlc_video_get_adjust_int(self.ptr, option.raw()) } } fn set_adjust_int(&self, option: VideoAdjustOption, value: i32) { - unsafe{ sys::libvlc_video_set_adjust_int(self.ptr, option as u32, value); } + unsafe{ sys::libvlc_video_set_adjust_int(self.ptr, option.raw(), value); } } fn get_adjust_float(&self, option: VideoAdjustOption) -> f32 { - unsafe{ sys::libvlc_video_get_adjust_float(self.ptr, option as u32) } + unsafe{ sys::libvlc_video_get_adjust_float(self.ptr, option.raw()) } } fn set_adjust_float(&self, option: VideoAdjustOption, value: f32) { - unsafe{ sys::libvlc_video_set_adjust_float(self.ptr, option as u32, value); } + unsafe{ sys::libvlc_video_set_adjust_float(self.ptr, option.raw(), value); } } }