macro to create linked list handling structure
parent
e7d7fe6740
commit
22ee272594
|
@ -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"
|
123
src/core.rs
123
src/core.rs
|
@ -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()) }
|
||||
}
|
||||
|
|
201
src/tools.rs
201
src/tools.rs
|
@ -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;
|
Loading…
Reference in New Issue