[vlc-devel] [RFC Patch v2 1/2] libvlc: Add Rust API for writing modules in rust

Alexandre Janniaux ajanni at videolabs.io
Tue Sep 15 10:24:07 CEST 2020


Hi,

I have a few additional points :)

On Sat, Sep 12, 2020 at 01:03:45AM +0530, Kartik Ohri wrote:
> The API is written in two layers. vlccore-sys
> crate contains one to one bindings of libvlc
> functions. vlccore-rs crate wraps vlccore-sys and
> exposes a Rust idiomatic API for writing modules
> in rust. As of now, the API exposes only a subset
> of the vlc_stream API. More functionality can be
> added to Rust API as required in the future.
> ---
>  .gitignore                    |   2 +-
>  configure.ac                  |  13 ++++
>  src/vlccore-rs/Cargo.toml     |  10 +++
>  src/vlccore-rs/src/lib.rs     |   1 +
>  src/vlccore-rs/src/stream.rs  | 120 ++++++++++++++++++++++++++++++++++
>  src/vlccore-sys/Cargo.toml    |  10 +++
>  src/vlccore-sys/src/lib.rs    |   2 +
>  src/vlccore-sys/src/stream.rs |  24 +++++++
>  8 files changed, 181 insertions(+), 1 deletion(-)
>  create mode 100644 src/vlccore-rs/Cargo.toml
>  create mode 100644 src/vlccore-rs/src/lib.rs
>  create mode 100644 src/vlccore-rs/src/stream.rs
>  create mode 100644 src/vlccore-sys/Cargo.toml
>  create mode 100644 src/vlccore-sys/src/lib.rs
>  create mode 100644 src/vlccore-sys/src/stream.rs
>
> diff --git a/.gitignore b/.gitignore
> index fc368212c8..6c049a80b1 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -46,7 +46,7 @@ wxvlc
>  vlc_install_dir/*
>  plugins.dat
>  patches/*
> -
> +**/Cargo.lock
>  include/vlc/libvlc_version.h
>
>  # Ignore build dirs
> diff --git a/configure.ac b/configure.ac
> index 99e4669942..53d56a725c 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1896,6 +1896,19 @@ AS_IF([test "${enable_sout}" != "no"], [
>  ])
>  AM_CONDITIONAL([ENABLE_SOUT], [test "${enable_sout}" != "no"])
>
> +dnl Rust Modules
> +AC_ARG_ENABLE([rust],
> +    AS_HELP_STRING([--enable-rust], [enable building Rust modules (default disabled)]))
> +AS_IF([test "${enable_rust}" = "yes"],
> +      [AC_DEFINE(ENABLE_RUST, 1, [Define to 1 for building rust modules.])])
> +AM_CONDITIONAL([BUILD_RUST], [test "${enable_rust}" = "yes"])
> +if test "${enable_rust}" = "yes"
> +then
> +    AC_CHECK_PROG(CARGO, [cargo], [yes], [no])
> +    AS_IF([test "x$CARGO" = "xno"],
> +          AC_MSG_ERROR([cargo not found. cargo is required to build rust modules]))
> +fi
> +
>  dnl Lua modules
>  AC_ARG_ENABLE([lua],
>    AS_HELP_STRING([--disable-lua],
> diff --git a/src/vlccore-rs/Cargo.toml b/src/vlccore-rs/Cargo.toml
> new file mode 100644
> index 0000000000..108c849f80
> --- /dev/null
> +++ b/src/vlccore-rs/Cargo.toml
> @@ -0,0 +1,10 @@
> +[package]
> +name = "vlccore-rs"
> +version = "0.1.0"
> +authors = ["Kartik Ohri <kartikohri13 at gmail.com>"]
> +edition = "2018"
> +license = "LGPL-2.1-or-later"
> +
> +[dependencies]
> +libc = "0.2"
> +vlccore-sys = {path="../vlccore-sys"}
> \ No newline at end of file
> diff --git a/src/vlccore-rs/src/lib.rs b/src/vlccore-rs/src/lib.rs
> new file mode 100644
> index 0000000000..baf29e06ad
> --- /dev/null
> +++ b/src/vlccore-rs/src/lib.rs
> @@ -0,0 +1 @@
> +pub mod stream;
> diff --git a/src/vlccore-rs/src/stream.rs b/src/vlccore-rs/src/stream.rs
> new file mode 100644
> index 0000000000..0725a8fe6e
> --- /dev/null
> +++ b/src/vlccore-rs/src/stream.rs
> @@ -0,0 +1,120 @@
> +use libc::{c_char, c_void};
> +use std::ffi::{CStr, CString};
> +use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom};
> +use std::ptr::null_mut;
> +use vlccore_sys::stream as ffi;
> +
> +pub struct Stream {
> +    stream: *mut ffi::stream_t,
> +}
> +
> +impl Read for Stream {
> +    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
> +        let bytes_read: isize = unsafe {
> +            ffi::vlc_stream_Read(self.stream, buf.as_mut_ptr() as *mut c_void, buf.len())
> +        };
> +        if bytes_read < 0 {
> +            Err(Error::new(
> +                ErrorKind::Other,
> +                "Error while reading from stream",
> +            ))
> +        } else {
> +            Ok(bytes_read as usize)
> +        }
> +    }
> +}
> +
> +impl Seek for Stream {
> +    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
> +        let offset = match pos {
> +            SeekFrom::Start(n) => n,
> +            SeekFrom::Current(n) => {
> +                let len = self.position();
> +                if n >= 0 {
> +                    len.checked_add(n as u64)
> +                } else {
> +                    len.checked_sub(n.wrapping_neg() as u64)
> +                }
> +                .ok_or(Error::new(ErrorKind::Other, "Position Overflow"))?
> +            }
> +            SeekFrom::End(n) => self.len().and_then(|position| {
> +                if n >= 0 {
> +                    position.checked_add(n as u64)
> +                } else {
> +                    position.checked_sub(n.wrapping_neg() as u64)
> +                }
> +                .ok_or(Error::new(ErrorKind::Other, "Position Overflow"))
> +            })?,
> +        };
> +
> +        let result = unsafe { ffi::vlc_stream_Seek(self.stream, offset) };
> +        if result != 0 {
> +            return Err(Error::new(ErrorKind::Other, "Could not seek stream"));
> +        }
> +        Ok(offset)
> +    }
> +}
> +
> +impl Drop for Stream {
> +    fn drop(&mut self) {
> +        unsafe { ffi::vlc_stream_Delete(self.stream) }
> +    }
> +}
> +
> +impl From<*mut ffi::stream_t> for Stream {
> +    fn from(stream: *mut ffi::stream_t) -> Self {
> +        Stream { stream }
> +    }
> +}
> +
> +impl Stream {
> +    pub fn len(&self) -> std::result::Result<u64, Error> {
> +        let size: u64 = 0;
> +        const STREAM_GET_SIZE: i32 = 6;
> +        let result = unsafe { ffi::vlc_stream_vaControl(self.stream, STREAM_GET_SIZE, &size) };
> +        if result != 0 {
> +            return Err(Error::new(
> +                ErrorKind::Other,
> +                "Could not determine stream size",
> +            ));
> +        }
> +        Ok(size)
> +    }
> +
> +    pub fn position(&self) -> u64 {
> +        unsafe { ffi::vlc_stream_Tell(self.stream) }
> +    }
> +
> +    pub fn eof(&self) -> Result<bool> {
> +        Ok(unsafe { ffi::vlc_stream_Eof(self.stream) })
> +    }
> +
> +    pub fn mimetype(&self) -> Option<String> {
> +        self.contenttype().map(|content_type| {
> +            let index = content_type.chars().position(|c| c == ';').unwrap();
> +            let mime_type: String = content_type[..index].to_owned();
> +            mime_type
> +        })

Since you don't chain map, you can probably just use early return here.

    pub fn mimetype(&self) -> Option<String> {
        let contenttype = self.contenttype()?;
        let index = content_type.chars().position(|c| c == ';')?;
        Some(content_type[..index].to_owned())
    }

> +    }
> +
> +    pub fn contenttype(&self) -> Option<String> {
> +        // FIXME: STREAM_GET_CONTENT_TYPE does not have a fixed value
> +        const STREAM_GET_CONTENT_TYPE: i32 = 0;
> +        let result: *mut c_char = null_mut();
> +        unsafe {
> +            if ffi::vlc_stream_vaControl(self.stream, STREAM_GET_CONTENT_TYPE, result) != 0 {
> +                return None;
> +            } else if result.is_null() {
> +                return None;
> +            }
> +            // FIXME: Free the C pointer received but retain copy of data in Rust
> +            CStr::from_ptr(result).to_str().map(|s| s.to_string()).ok()
> +        }
> +    }
> +
> +    pub fn new_with_url(&mut self, url: &str) -> Self {
> +        let c_url = CString::new(url).unwrap().as_ptr();
> +        let stream = unsafe { ffi::vlc_stream_NewURL(self.stream, c_url) };
> +        Stream { stream }
> +    }
> +}
> diff --git a/src/vlccore-sys/Cargo.toml b/src/vlccore-sys/Cargo.toml
> new file mode 100644
> index 0000000000..0dde7b2e7d
> --- /dev/null
> +++ b/src/vlccore-sys/Cargo.toml
> @@ -0,0 +1,10 @@
> +[package]
> +name = "vlccore-sys"
> +version = "0.1.0"
> +authors = ["Kartik Ohri <kartikohri13 at gmail.com>"]
> +edition = "2018"
> +license = "LGPL-2.1-or-later"
> +
> +[dependencies]
> +libc = "0.2"
> +
> diff --git a/src/vlccore-sys/src/lib.rs b/src/vlccore-sys/src/lib.rs
> new file mode 100644
> index 0000000000..42a75452cd
> --- /dev/null
> +++ b/src/vlccore-sys/src/lib.rs
> @@ -0,0 +1,2 @@
> +#![allow(non_camel_case_types)]
> +pub mod stream;
> diff --git a/src/vlccore-sys/src/stream.rs b/src/vlccore-sys/src/stream.rs
> new file mode 100644
> index 0000000000..c9e8d5f0b3
> --- /dev/null
> +++ b/src/vlccore-sys/src/stream.rs
> @@ -0,0 +1,24 @@
> +use libc::{c_char, c_int, c_void, size_t, ssize_t};
> +
> +#[repr(C)]
> +pub struct stream_t {
> +    _private: [u8; 0],
> +}
> +
> +pub type vlc_object_t = stream_t;
> +
> +extern "C" {
> +    pub fn vlc_stream_Read(s: *mut stream_t, buf: *mut c_void, len: size_t) -> ssize_t;
> +
> +    pub fn vlc_stream_Tell(s: *const stream_t) -> u64;
> +
> +    pub fn vlc_stream_Eof(s: *const stream_t) -> bool;
> +
> +    pub fn vlc_stream_Seek(s: *mut stream_t, offset: u64) -> c_int;
> +
> +    pub fn vlc_stream_vaControl(s: *mut stream_t, query: c_int, ...) -> c_int;

After checking [1], you probably need the following code instead:

    extern "C" {
        pub unsafe fn vlc_stream_vaControl(s: *mut stream_t, query: c_int, ap: VaList) -> c_int;
    }
    pub unsafe fn vlc_stream_Control(s: *mut stream_t, query: c_int, mut args: ...) -> c_int {
        vlc_stream_vaControl(s, query, args)
    }

Otherwise, as far as I understand this document, va_start/va_end might not be called correctly.
I haven't checked in details though, and it needs the #![feature(c_variadic)] attribute.

[1] https://github.com/rust-lang/rfcs/blob/26197104b7bb9a5a35db243d639aee6e46d35d75/text/2137-variadic.md

> +
> +    pub fn vlc_stream_Delete(s: *mut stream_t);
> +
> +    pub fn vlc_stream_NewURL(obj: *mut vlc_object_t, url: *const c_char) -> *mut stream_t;
> +}
> --
> 2.25.1
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


Regards,
--
Alexandre Janniaux
Videolabs


More information about the vlc-devel mailing list