musikr: fix iostream pinning

This commit is contained in:
Alexander Capehart 2025-02-14 15:14:14 -07:00
parent 74edd1dbdf
commit 249915c3be
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
5 changed files with 79 additions and 83 deletions

View file

@ -1,4 +1,4 @@
use crate::taglib::stream::IOStream; use crate::taglib::file::IOStream;
use jni::objects::{JObject, JValue}; use jni::objects::{JObject, JValue};
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Read, Seek, SeekFrom, Write};
use crate::SharedEnv; use crate::SharedEnv;

View file

@ -1,20 +1,18 @@
use super::stream::BridgeStream;
#[cxx::bridge] #[cxx::bridge]
mod bridge_impl { mod bridge_impl {
// Expose Rust IOStream to C++ // Expose Rust IOStream to C++
extern "Rust" { extern "Rust" {
#[cxx_name = "BridgeStream"] #[cxx_name = "BridgeStream"]
type BridgeStream<'a>; type TIOStream<'a>;
fn name(self: &mut BridgeStream<'_>) -> String; fn name(self: &mut TIOStream<'_>) -> String;
fn read(self: &mut BridgeStream<'_>, buffer: &mut [u8]) -> usize; fn read(self: &mut TIOStream<'_>, buffer: &mut [u8]) -> usize;
fn write(self: &mut BridgeStream<'_>, data: &[u8]); fn write(self: &mut TIOStream<'_>, data: &[u8]);
fn seek(self: &mut BridgeStream<'_>, offset: i64, whence: i32); fn seek(self: &mut TIOStream<'_>, offset: i64, whence: i32);
fn truncate(self: &mut BridgeStream<'_>, length: i64); fn truncate(self: &mut TIOStream<'_>, length: i64);
fn tell(self: &mut BridgeStream<'_>) -> i64; fn tell(self: &mut TIOStream<'_>) -> i64;
fn length(self: &mut BridgeStream<'_>) -> i64; fn length(self: &mut TIOStream<'_>) -> i64;
fn is_readonly(self: &BridgeStream<'_>) -> bool; fn is_readonly(self: &TIOStream<'_>) -> bool;
} }
#[namespace = "taglib_shim"] #[namespace = "taglib_shim"]
@ -40,7 +38,7 @@ mod bridge_impl {
fn thisFile(self: Pin<&TFileRef>) -> *mut BaseFile; fn thisFile(self: Pin<&TFileRef>) -> *mut BaseFile;
// Create a RustIOStream from a BridgeStream // Create a RustIOStream from a BridgeStream
unsafe fn new_RustIOStream(stream: Pin<&mut BridgeStream>) -> UniquePtr<RustIOStream>; unsafe fn new_RustIOStream(stream: Pin<&mut TIOStream>) -> UniquePtr<RustIOStream>;
// Create a FileRef from an iostream // Create a FileRef from an iostream
fn new_FileRef_from_stream(stream: UniquePtr<RustIOStream>) -> UniquePtr<TFileRef>; fn new_FileRef_from_stream(stream: UniquePtr<RustIOStream>) -> UniquePtr<TFileRef>;
@ -154,3 +152,60 @@ mod bridge_impl {
} }
pub use bridge_impl::*; pub use bridge_impl::*;
use std::io::SeekFrom;
use std::pin::Pin;
use super::file::IOStream;
#[repr(C)]
pub(super) struct TIOStream<'a>(Box<dyn IOStream + 'a>);
impl<'a> TIOStream<'a> {
pub fn new<T: IOStream + 'a>(stream: T) -> Pin<Box<Self>> {
Box::pin(TIOStream(Box::new(stream)))
}
// Implement the exposed functions for cxx bridge
pub fn name(&mut self) -> String {
self.0.name()
}
pub fn read(&mut self, buffer: &mut [u8]) -> usize {
self.0.read(buffer).unwrap_or(0)
}
pub fn write(&mut self, data: &[u8]) {
self.0.write_all(data).unwrap();
}
pub fn seek(&mut self, offset: i64, whence: i32) {
let pos = match whence {
0 => SeekFrom::Start(offset as u64),
1 => SeekFrom::Current(offset),
2 => SeekFrom::End(offset),
_ => panic!("Invalid seek whence"),
};
self.0.seek(pos).unwrap();
}
pub fn truncate(&mut self, length: i64) {
self.0.seek(SeekFrom::Start(length as u64)).unwrap();
// TODO: Actually implement truncate once we have a better trait bound
}
pub fn tell(&mut self) -> i64 {
self.0.seek(SeekFrom::Current(0)).unwrap() as i64
}
pub fn length(&mut self) -> i64 {
let current = self.0.seek(SeekFrom::Current(0)).unwrap();
let end = self.0.seek(SeekFrom::End(0)).unwrap();
self.0.seek(SeekFrom::Start(current)).unwrap();
end as i64
}
pub fn is_readonly(&self) -> bool {
self.0.is_readonly()
}
}

View file

@ -1,21 +1,19 @@
use cxx::UniquePtr; use cxx::UniquePtr;
use super::bridge::{self, TFileRef}; use super::bridge::{self, TFileRef, TIOStream};
pub use super::bridge::{BaseFile as File, AudioProperties}; pub use super::bridge::{BaseFile as File, AudioProperties};
use super::xiph::{OpusFile, VorbisFile, FLACFile}; use super::xiph::{OpusFile, VorbisFile, FLACFile};
use super::stream::BridgeStream; use std::io::{Read, Write, Seek};
use super::stream::IOStream;
use std::pin::Pin; use std::pin::Pin;
use std::marker::PhantomData;
pub struct FileRef<'a> { pub struct FileRef<'a> {
stream: BridgeStream<'a>, stream: Pin<Box<TIOStream<'a>>>,
file_ref: UniquePtr<TFileRef> file_ref: UniquePtr<TFileRef>
} }
impl <'a> FileRef<'a> { impl <'a> FileRef<'a> {
pub fn new<T : IOStream + 'a>(stream: T) -> FileRef<'a> { pub fn new<T : IOStream + 'a>(stream: T) -> FileRef<'a> {
let mut bridge_stream = BridgeStream::new(stream); let mut bridge_stream = TIOStream::new(stream);
let iostream = unsafe { bridge::new_RustIOStream(Pin::new(&mut bridge_stream)) }; let iostream = unsafe { bridge::new_RustIOStream(bridge_stream.as_mut()) };
let file_ref = bridge::new_FileRef_from_stream(iostream); let file_ref = bridge::new_FileRef_from_stream(iostream);
FileRef { FileRef {
stream: bridge_stream, stream: bridge_stream,
@ -196,4 +194,9 @@ impl <'a> Drop for FileRef<'a> {
std::ptr::drop_in_place(&mut self.stream); std::ptr::drop_in_place(&mut self.stream);
} }
} }
} }
pub trait IOStream: Read + Write + Seek {
fn name(&mut self) -> String;
fn is_readonly(&self) -> bool;
}

View file

@ -1,6 +1,5 @@
mod bridge; mod bridge;
pub mod file; pub mod file;
pub mod stream;
pub mod tk; pub mod tk;
pub mod xiph; pub mod xiph;

View file

@ -1,61 +0,0 @@
use std::ffi::{c_void, CString};
use std::io::{Read, Seek, SeekFrom, Write};
use std::os::raw::c_char;
use cxx::CxxString;
pub trait IOStream: Read + Write + Seek {
fn name(&mut self) -> String;
fn is_readonly(&self) -> bool;
}
#[repr(C)]
pub(super) struct BridgeStream<'a>(Box<dyn IOStream + 'a>);
impl<'a> BridgeStream<'a> {
pub fn new<T: IOStream + 'a>(stream: T) -> Self {
BridgeStream(Box::new(stream))
}
// Implement the exposed functions for cxx bridge
pub fn name(&mut self) -> String {
self.0.name()
}
pub fn read(&mut self, buffer: &mut [u8]) -> usize {
self.0.read(buffer).unwrap_or(0)
}
pub fn write(&mut self, data: &[u8]) {
self.0.write_all(data).unwrap();
}
pub fn seek(&mut self, offset: i64, whence: i32) {
let pos = match whence {
0 => SeekFrom::Start(offset as u64),
1 => SeekFrom::Current(offset),
2 => SeekFrom::End(offset),
_ => panic!("Invalid seek whence"),
};
self.0.seek(pos).unwrap();
}
pub fn truncate(&mut self, length: i64) {
self.0.seek(SeekFrom::Start(length as u64)).unwrap();
// TODO: Actually implement truncate once we have a better trait bound
}
pub fn tell(&mut self) -> i64 {
self.0.seek(SeekFrom::Current(0)).unwrap() as i64
}
pub fn length(&mut self) -> i64 {
let current = self.0.seek(SeekFrom::Current(0)).unwrap();
let end = self.0.seek(SeekFrom::End(0)).unwrap();
self.0.seek(SeekFrom::Start(current)).unwrap();
end as i64
}
pub fn is_readonly(&self) -> bool {
self.0.is_readonly()
}
}