Merge branch 'fix/ffi-enum-forward-compat' into 'master'

Preserve unknown LibVLC enum values

See merge request videolan/vlc-rs!29
merge-requests/29/merge
Martin Finkel 2026-08-31 14:54:28 +00:00
commit 30caf0d3a9
5 changed files with 89 additions and 17 deletions

View File

@ -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<F>(&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
}
}

View File

@ -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<sys::$original_type> 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);
}
}

View File

@ -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<String> {
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<String>,
}

View File

@ -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<String>,
}

View File

@ -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); }
}
}