From 0ae5018c33cc4bfe27583c9902472b499f4bd269 Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Fri, 23 Aug 2024 12:57:19 +0200 Subject: refactor(libmpv2): Move to the `crates` directory --- libmpv2/src/mpv/protocol.rs | 261 -------------------------------------------- 1 file changed, 261 deletions(-) delete mode 100644 libmpv2/src/mpv/protocol.rs (limited to 'libmpv2/src/mpv/protocol.rs') diff --git a/libmpv2/src/mpv/protocol.rs b/libmpv2/src/mpv/protocol.rs deleted file mode 100644 index 4ae4f16..0000000 --- a/libmpv2/src/mpv/protocol.rs +++ /dev/null @@ -1,261 +0,0 @@ -// yt - A fully featured command line YouTube client -// -// Copyright (C) 2024 Benedikt Peetz -// SPDX-License-Identifier: GPL-3.0-or-later -// -// This file is part of Yt. -// -// You should have received a copy of the License along with this program. -// If not, see . - -use super::*; - -use std::alloc::{self, Layout}; -use std::marker::PhantomData; -use std::mem; -use std::os::raw as ctype; -use std::panic; -use std::panic::RefUnwindSafe; -use std::slice; -use std::sync::{atomic::Ordering, Mutex}; - -impl Mpv { - /// Create a context with which custom protocols can be registered. - /// - /// # Panics - /// Panics if a context already exists - pub fn create_protocol_context(&self) -> ProtocolContext - where - T: RefUnwindSafe, - U: RefUnwindSafe, - { - match self.protocols_guard.compare_exchange( - false, - true, - Ordering::AcqRel, - Ordering::Acquire, - ) { - Ok(_) => ProtocolContext::new(self.ctx, PhantomData::<&Self>), - Err(_) => panic!("A protocol context already exists"), - } - } -} - -/// Return a persistent `T` that is passed to all other `Stream*` functions, panic on errors. -pub type StreamOpen = fn(&mut U, &str) -> T; -/// Do any necessary cleanup. -pub type StreamClose = fn(Box); -/// Seek to the given offset. Return the new offset, or either `MpvError::Generic` if seeking -/// failed or panic. -pub type StreamSeek = fn(&mut T, i64) -> i64; -/// Target buffer with fixed capacity. -/// Return either the number of read bytes, `0` on EOF, or either `-1` or panic on error. -pub type StreamRead = fn(&mut T, &mut [ctype::c_char]) -> i64; -/// Return the total size of the stream in bytes. Panic on error. -pub type StreamSize = fn(&mut T) -> i64; - -unsafe extern "C" fn open_wrapper( - user_data: *mut ctype::c_void, - uri: *mut ctype::c_char, - info: *mut libmpv2_sys::mpv_stream_cb_info, -) -> ctype::c_int -where - T: RefUnwindSafe, - U: RefUnwindSafe, -{ - let data = user_data as *mut ProtocolData; - - (*info).cookie = user_data; - (*info).read_fn = Some(read_wrapper::); - (*info).seek_fn = Some(seek_wrapper::); - (*info).size_fn = Some(size_wrapper::); - (*info).close_fn = Some(close_wrapper::); - - let ret = panic::catch_unwind(|| { - let uri = mpv_cstr_to_str!(uri as *const _).unwrap(); - ptr::write( - (*data).cookie, - ((*data).open_fn)(&mut (*data).user_data, uri), - ); - }); - - if ret.is_ok() { - 0 - } else { - mpv_error::Generic as _ - } -} - -unsafe extern "C" fn read_wrapper( - cookie: *mut ctype::c_void, - buf: *mut ctype::c_char, - nbytes: u64, -) -> i64 -where - T: RefUnwindSafe, - U: RefUnwindSafe, -{ - let data = cookie as *mut ProtocolData; - - let ret = panic::catch_unwind(|| { - let slice = slice::from_raw_parts_mut(buf, nbytes as _); - ((*data).read_fn)(&mut *(*data).cookie, slice) - }); - if let Ok(ret) = ret { - ret - } else { - -1 - } -} - -unsafe extern "C" fn seek_wrapper(cookie: *mut ctype::c_void, offset: i64) -> i64 -where - T: RefUnwindSafe, - U: RefUnwindSafe, -{ - let data = cookie as *mut ProtocolData; - - if (*data).seek_fn.is_none() { - return mpv_error::Unsupported as _; - } - - let ret = - panic::catch_unwind(|| (*(*data).seek_fn.as_ref().unwrap())(&mut *(*data).cookie, offset)); - if let Ok(ret) = ret { - ret - } else { - mpv_error::Generic as _ - } -} - -unsafe extern "C" fn size_wrapper(cookie: *mut ctype::c_void) -> i64 -where - T: RefUnwindSafe, - U: RefUnwindSafe, -{ - let data = cookie as *mut ProtocolData; - - if (*data).size_fn.is_none() { - return mpv_error::Unsupported as _; - } - - let ret = panic::catch_unwind(|| (*(*data).size_fn.as_ref().unwrap())(&mut *(*data).cookie)); - if let Ok(ret) = ret { - ret - } else { - mpv_error::Unsupported as _ - } -} - -#[allow(unused_must_use)] -unsafe extern "C" fn close_wrapper(cookie: *mut ctype::c_void) -where - T: RefUnwindSafe, - U: RefUnwindSafe, -{ - let data = Box::from_raw(cookie as *mut ProtocolData); - - panic::catch_unwind(|| ((*data).close_fn)(Box::from_raw((*data).cookie))); -} - -struct ProtocolData { - cookie: *mut T, - user_data: U, - - open_fn: StreamOpen, - close_fn: StreamClose, - read_fn: StreamRead, - seek_fn: Option>, - size_fn: Option>, -} - -/// This context holds state relevant to custom protocols. -/// It is created by calling `Mpv::create_protocol_context`. -pub struct ProtocolContext<'parent, T: RefUnwindSafe, U: RefUnwindSafe> { - ctx: NonNull, - protocols: Mutex>>, - _does_not_outlive: PhantomData<&'parent Mpv>, -} - -unsafe impl<'parent, T: RefUnwindSafe, U: RefUnwindSafe> Send for ProtocolContext<'parent, T, U> {} -unsafe impl<'parent, T: RefUnwindSafe, U: RefUnwindSafe> Sync for ProtocolContext<'parent, T, U> {} - -impl<'parent, T: RefUnwindSafe, U: RefUnwindSafe> ProtocolContext<'parent, T, U> { - fn new( - ctx: NonNull, - marker: PhantomData<&'parent Mpv>, - ) -> ProtocolContext<'parent, T, U> { - ProtocolContext { - ctx, - protocols: Mutex::new(Vec::new()), - _does_not_outlive: marker, - } - } - - /// Register a custom `Protocol`. Once a protocol has been registered, it lives as long as - /// `Mpv`. - /// - /// Returns `Error::Mpv(MpvError::InvalidParameter)` if a protocol with the same name has - /// already been registered. - pub fn register(&self, protocol: Protocol) -> Result<()> { - let mut protocols = self.protocols.lock().unwrap(); - protocol.register(self.ctx.as_ptr())?; - protocols.push(protocol); - Ok(()) - } -} - -/// `Protocol` holds all state used by a custom protocol. -pub struct Protocol { - name: String, - data: *mut ProtocolData, -} - -impl Protocol { - /// `name` is the prefix of the protocol, e.g. `name://path`. - /// - /// `user_data` is data that will be passed to `open_fn`. - /// - /// # Safety - /// Do not call libmpv functions in any supplied function. - /// All panics of the provided functions are catched and can be used as generic error returns. - pub unsafe fn new( - name: String, - user_data: U, - open_fn: StreamOpen, - close_fn: StreamClose, - read_fn: StreamRead, - seek_fn: Option>, - size_fn: Option>, - ) -> Protocol { - let c_layout = Layout::from_size_align(mem::size_of::(), mem::align_of::()).unwrap(); - let cookie = alloc::alloc(c_layout) as *mut T; - let data = Box::into_raw(Box::new(ProtocolData { - cookie, - user_data, - - open_fn, - close_fn, - read_fn, - seek_fn, - size_fn, - })); - - Protocol { name, data } - } - - fn register(&self, ctx: *mut libmpv2_sys::mpv_handle) -> Result<()> { - let name = CString::new(&self.name[..])?; - unsafe { - mpv_err( - (), - libmpv2_sys::mpv_stream_cb_add_ro( - ctx, - name.as_ptr(), - self.data as *mut _, - Some(open_wrapper::), - ), - ) - } - } -} -- cgit 1.4.1