macro to create linked list handling structure

6-output_list_wrappers-macro
Pierre Réveillon 2021-11-22 17:37:39 +01:00
parent e7d7fe6740
commit 22ee272594
3 changed files with 235 additions and 90 deletions

View File

@ -20,6 +20,7 @@ crate-type = ["rlib"]
[dependencies]
libc = "0.2"
libvlc-sys = "0.2"
paste = "1.0"
[target.'cfg(target_os = "windows")'.build-dependencies]
vswhom = "0.1.0"

View File

@ -3,14 +3,13 @@
// Licensed under the MIT license, see the LICENSE file.
use crate::enums::*;
use crate::tools::{from_cstr, from_cstr_ref, to_cstr};
use crate::tools::{from_cstr, from_cstr_ref, linked_list_iter, to_cstr};
use libc::{c_char, c_int, c_void};
use std::borrow::Cow;
use std::convert::TryInto;
use std::ffi::CString;
use std::fmt;
use std::i32;
use std::marker::PhantomData;
use std::ptr;
use vlc_sys as sys;
@ -25,6 +24,36 @@ impl fmt::Display for InternalError {
impl std::error::Error for InternalError {}
linked_list_iter!(
libvlc_module_description, // C raw type
module_description, // Rust base struct name
{
name: (String, str),
shortname: (String, str),
longname: (String, str),
help: (String, str),
} // fields
);
linked_list_iter!(
libvlc_audio_output, // C raw type
audio_output, // Rust base struct name
{
name: (String, str),
description: (String, str),
} // fields
);
linked_list_iter!(
libvlc_audio_output_device, // C raw type
audio_output_device, // Rust base struct name
{
device: (String, str),
description: (String, str),
} // fields
);
/// Retrieve libvlc version.
pub fn version() -> String {
unsafe {
@ -131,7 +160,7 @@ impl Instance {
if p.is_null() {
None
} else {
Some(ModuleDescriptionList { ptr: p })
Some(ModuleDescriptionList::new(p))
}
}
}
@ -143,7 +172,7 @@ impl Instance {
if p.is_null() {
None
} else {
Some(ModuleDescriptionList { ptr: p })
Some(ModuleDescriptionList::new(p))
}
}
}
@ -203,92 +232,6 @@ unsafe extern "C" fn logging_cb(
);
}
/// List of module description.
pub struct ModuleDescriptionList {
ptr: *mut sys::libvlc_module_description_t,
}
impl ModuleDescriptionList {
/// Returns raw pointer
pub fn raw(&self) -> *mut sys::libvlc_module_description_t {
self.ptr
}
}
impl Drop for ModuleDescriptionList {
fn drop(&mut self) {
unsafe { sys::libvlc_module_description_list_release(self.ptr) };
}
}
impl<'a> IntoIterator for &'a ModuleDescriptionList {
type Item = ModuleDescriptionRef<'a>;
type IntoIter = ModuleDescriptionListIter<'a>;
fn into_iter(self) -> Self::IntoIter {
ModuleDescriptionListIter {
ptr: self.ptr,
_phantomdata: PhantomData,
}
}
}
pub struct ModuleDescriptionListIter<'a> {
ptr: *mut sys::libvlc_module_description_t,
_phantomdata: PhantomData<&'a sys::libvlc_module_description_t>,
}
/// Description of a module.
/// The strings are owned.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct ModuleDescription {
pub name: Option<String>,
pub shortname: Option<String>,
pub longname: Option<String>,
pub help: Option<String>,
}
/// Description of a module.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct ModuleDescriptionRef<'a> {
pub name: Option<Cow<'a, str>>,
pub shortname: Option<Cow<'a, str>>,
pub longname: Option<Cow<'a, str>>,
pub help: Option<Cow<'a, str>>,
}
impl<'a> Iterator for ModuleDescriptionListIter<'a> {
type Item = ModuleDescriptionRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if self.ptr.is_null() {
return None;
}
let p = self.ptr;
self.ptr = (*p).p_next;
Some(ModuleDescriptionRef {
name: from_cstr_ref((*p).psz_name),
shortname: from_cstr_ref((*p).psz_shortname),
longname: from_cstr_ref((*p).psz_longname),
help: from_cstr_ref((*p).psz_help),
})
}
}
}
impl<'a> ModuleDescriptionRef<'a> {
/// Convert to owned strings.
pub fn into_owned(&'a self) -> ModuleDescription {
ModuleDescription {
name: self.name.as_ref().map(|s| s.clone().into_owned()),
shortname: self.shortname.as_ref().map(|s| s.clone().into_owned()),
longname: self.name.as_ref().map(|s| s.clone().into_owned()),
help: self.shortname.as_ref().map(|s| s.clone().into_owned()),
}
}
}
pub fn errmsg() -> Option<String> {
unsafe { from_cstr(sys::libvlc_errmsg()) }
}

View File

@ -41,3 +41,204 @@ pub fn path_to_cstr(path: &Path) -> Result<CString, NulError> {
Ok(path)
}
/// Defines a module with all necessary structures to easily handle a C linked list
macro_rules! linked_list_iter {
(
$c_type:ident,
$name:ident,
{
$($(#[$field_meta:meta])*
$field_vis:vis $field_name:ident: ($field_type:ty, $field_b_type:ty)),* $(,)+
}
) => {
paste::item! {
mod $name {
use std::borrow::Cow;
use std::marker::PhantomData;
use crate::tools::from_cstr_ref;
use vlc_sys::[<$c_type _t>];
use vlc_sys::[<$c_type _list_release>];
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Item {
$(
$(#[$field_meta:meta])*
$field_vis $field_name : Option<$field_type>,
)*
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct ItemRef<'a> {
$(
$(#[$field_meta:meta])*
$field_vis $field_name : Option<Cow<'a, $field_b_type>>,
)*
}
impl<'a> ItemRef<'a> {
/// Convert to owned strings.
pub fn into_owned(&'a self) -> Item {
Item {
$($field_name: self.$field_name.as_ref().map(|s| s.clone().into_owned()),)*
}
}
}
pub struct ListIter<'a> {
ptr: *mut [<$c_type _t>],
_phantomdata: PhantomData<&'a [<$c_type _t>]>,
}
impl<'a> Iterator for ListIter<'a> {
type Item = ItemRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if self.ptr.is_null() {
return None;
}
let p = self.ptr;
self.ptr = (*p).p_next;
Some(ItemRef {
$($field_name: from_cstr_ref((*p).[<psz_ $field_name>]),)*
})
}
}
}
pub struct List {
ptr: *mut [<$c_type _t>]
}
impl List {
pub fn new(ptr: *mut [<$c_type _t>]) -> List {
Self { ptr }
}
/// Returns raw pointer
pub fn raw(&self) -> *mut [<$c_type _t>] {
self.ptr
}
}
impl Drop for List {
fn drop(&mut self) {
unsafe{ [<$c_type _list_release>](self.ptr) };
}
}
impl<'a> IntoIterator for &'a List {
type Item = ItemRef<'a>;
type IntoIter = ListIter<'a>;
fn into_iter(self) -> Self::IntoIter {
ListIter{ptr: self.ptr, _phantomdata: PhantomData}
}
}
}
// backward compatibility types
pub type [<$name:camel>] = $name::Item;
pub type [<$name:camel Ref>]<'a> = $name::ItemRef<'a>;
pub type [<$name:camel List>] = $name::List;
pub type [<$name:camel ListIter>]<'a> = $name::ListIter<'a>;
}
}
}
/*
macro_rules! linked_list_iter {
(
$namespace:path,
$c_type: ident,
$name: ident,
{
$($(#[$field_meta:meta])*
$field_vis:vis $field_name:ident: ($field_type:ty, $field_b_type:ty)),* $(,)+
}
) => {
paste::item! {
use std::marker::PhantomData;
use crate::$namespace::[<$c_type _t>];
use crate::$namespace::[<$c_type _list_release>];
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
$(
$(#[$field_meta:meta])*
$field_vis $field_name : Option<$field_type>,
)*
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct [<$name Ref>]<'a> {
$(
$(#[$field_meta:meta])*
$field_vis $field_name : Option<Cow<'a, $field_b_type>>,
)*
}
impl<'a> [<$name Ref>]<'a> {
/// Convert to owned strings.
pub fn into_owned(&'a self) -> $name {
$name {
$($field_name: self.$field_name.as_ref().map(|s| s.clone().into_owned()),)*
}
}
}
pub struct [<$name ListIter>]<'a> {
ptr: *mut [<$c_type _t>],
_phantomdata: PhantomData<&'a [<$c_type _t>]>,
}
impl<'a> Iterator for [<$name ListIter>]<'a> {
type Item = [<$name Ref>]<'a>;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if self.ptr.is_null() {
return None;
}
let p = self.ptr;
self.ptr = (*p).p_next;
Some([<$name Ref>] {
$($field_name: from_cstr_ref((*p).[<psz_ $field_name>]),)*
})
}
}
}
pub struct [<$name List>] {
ptr: *mut [<$c_type _t>]
}
impl [<$name List>] {
/// Returns raw pointer
pub fn raw(&self) -> *mut [<$c_type _t>] {
self.ptr
}
}
impl Drop for [<$name List>] {
fn drop(&mut self) {
unsafe{ [<$c_type _list_release>](self.ptr) };
}
}
impl<'a> IntoIterator for &'a [<$name List>] {
type Item = [<$name Ref>]<'a>;
type IntoIter = [<$name ListIter>]<'a>;
fn into_iter(self) -> Self::IntoIter {
[<$name ListIter>]{ptr: self.ptr, _phantomdata: PhantomData}
}
}
}
}
}
*/
pub(crate) use linked_list_iter;