musikr: improve iostream lifecycle mgmt
This commit is contained in:
parent
249915c3be
commit
7906fcf5af
9 changed files with 170 additions and 153 deletions
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace taglib_shim
|
namespace taglib_shim
|
||||||
{
|
{
|
||||||
|
std::unique_ptr<TagLib::FileRef> new_FileRef(std::unique_ptr<TagLib::IOStream> stream) {
|
||||||
|
return std::make_unique<TagLib::FileRef>(stream.release());
|
||||||
|
}
|
||||||
|
|
||||||
TagLib::Ogg::Vorbis::File *File_asVorbis(TagLib::File *file)
|
TagLib::Ogg::Vorbis::File *File_asVorbis(TagLib::File *file)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
namespace taglib_shim
|
namespace taglib_shim
|
||||||
{
|
{
|
||||||
|
std::unique_ptr<TagLib::FileRef> new_FileRef(TagLib::IOStream *stream);
|
||||||
|
|
||||||
TagLib::Ogg::Vorbis::File *File_asVorbis(TagLib::File *file);
|
TagLib::Ogg::Vorbis::File *File_asVorbis(TagLib::File *file);
|
||||||
TagLib::Ogg::Opus::File *File_asOpus(TagLib::File *file);
|
TagLib::Ogg::Opus::File *File_asOpus(TagLib::File *file);
|
||||||
|
|
|
@ -4,57 +4,57 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "metadatajni/src/taglib/bridge.rs.h"
|
#include "metadatajni/src/taglib/bridge.rs.h"
|
||||||
|
|
||||||
// These are the functions we'll define in Rust
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
const char *rust_stream_name(const void *stream);
|
|
||||||
size_t rust_stream_read(void *stream, uint8_t *buffer, size_t length);
|
|
||||||
void rust_stream_write(void *stream, const uint8_t *data, size_t length);
|
|
||||||
void rust_stream_seek(void *stream, int64_t offset, int32_t whence);
|
|
||||||
void rust_stream_truncate(void *stream, int64_t length);
|
|
||||||
int64_t rust_stream_tell(const void *stream);
|
|
||||||
int64_t rust_stream_length(const void *stream);
|
|
||||||
bool rust_stream_is_readonly(const void *stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace taglib_shim
|
namespace taglib_shim
|
||||||
{
|
{
|
||||||
|
|
||||||
// Factory function to create a new RustIOStream
|
// C++ implementation of TagLib::IOStream that delegates to Rust
|
||||||
std::unique_ptr<RustIOStream> new_RustIOStream(BridgeStream& stream)
|
class WrappedRsIOStream : public TagLib::IOStream
|
||||||
{
|
{
|
||||||
return std::unique_ptr<RustIOStream>(new RustIOStream(stream));
|
public:
|
||||||
}
|
explicit WrappedRsIOStream(RsIOStream& stream);
|
||||||
|
~WrappedRsIOStream() override;
|
||||||
|
|
||||||
// Factory function to create a FileRef from a stream
|
// TagLib::IOStream interface implementation
|
||||||
std::unique_ptr<TagLib::FileRef> new_FileRef_from_stream(std::unique_ptr<RustIOStream> stream)
|
TagLib::FileName name() const override;
|
||||||
{
|
TagLib::ByteVector readBlock(size_t length) override;
|
||||||
return std::make_unique<TagLib::FileRef>(stream.release(), true);
|
void writeBlock(const TagLib::ByteVector &data) override;
|
||||||
}
|
void insert(const TagLib::ByteVector &data, TagLib::offset_t start = 0, size_t replace = 0) override;
|
||||||
|
void removeBlock(TagLib::offset_t start = 0, size_t length = 0) override;
|
||||||
|
void seek(TagLib::offset_t offset, Position p = Beginning) override;
|
||||||
|
void clear() override;
|
||||||
|
void truncate(TagLib::offset_t length) override;
|
||||||
|
TagLib::offset_t tell() const override;
|
||||||
|
TagLib::offset_t length() override;
|
||||||
|
bool readOnly() const override;
|
||||||
|
bool isOpen() const override;
|
||||||
|
|
||||||
RustIOStream::RustIOStream(BridgeStream& stream) : rust_stream(stream) {}
|
private:
|
||||||
|
RsIOStream& rust_stream;
|
||||||
|
};
|
||||||
|
|
||||||
RustIOStream::~RustIOStream() = default;
|
WrappedRsIOStream::WrappedRsIOStream(RsIOStream& stream) : rust_stream(stream) {}
|
||||||
|
|
||||||
TagLib::FileName RustIOStream::name() const
|
WrappedRsIOStream::~WrappedRsIOStream() = default;
|
||||||
|
|
||||||
|
TagLib::FileName WrappedRsIOStream::name() const
|
||||||
{
|
{
|
||||||
return rust::string(rust_stream.name()).c_str();
|
return rust::string(rust_stream.name()).c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
TagLib::ByteVector RustIOStream::readBlock(size_t length)
|
TagLib::ByteVector WrappedRsIOStream::readBlock(size_t length)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> buffer(length);
|
std::vector<uint8_t> buffer(length);
|
||||||
size_t bytes_read = rust_stream.read(rust::Slice<uint8_t>(buffer.data(), length));
|
size_t bytes_read = rust_stream.read(rust::Slice<uint8_t>(buffer.data(), length));
|
||||||
return TagLib::ByteVector(reinterpret_cast<char *>(buffer.data()), bytes_read);
|
return TagLib::ByteVector(reinterpret_cast<char *>(buffer.data()), bytes_read);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RustIOStream::writeBlock(const TagLib::ByteVector &data)
|
void WrappedRsIOStream::writeBlock(const TagLib::ByteVector &data)
|
||||||
{
|
{
|
||||||
rust_stream.write(rust::Slice<const uint8_t>(
|
rust_stream.write(rust::Slice<const uint8_t>(
|
||||||
reinterpret_cast<const uint8_t *>(data.data()), data.size()));
|
reinterpret_cast<const uint8_t *>(data.data()), data.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RustIOStream::insert(const TagLib::ByteVector &data, TagLib::offset_t start, size_t replace)
|
void WrappedRsIOStream::insert(const TagLib::ByteVector &data, TagLib::offset_t start, size_t replace)
|
||||||
{
|
{
|
||||||
// Save current position
|
// Save current position
|
||||||
auto current = tell();
|
auto current = tell();
|
||||||
|
@ -75,7 +75,7 @@ namespace taglib_shim
|
||||||
seek(current);
|
seek(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RustIOStream::removeBlock(TagLib::offset_t start, size_t length)
|
void WrappedRsIOStream::removeBlock(TagLib::offset_t start, size_t length)
|
||||||
{
|
{
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -101,7 +101,7 @@ namespace taglib_shim
|
||||||
seek(current);
|
seek(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RustIOStream::seek(TagLib::offset_t offset, Position p)
|
void WrappedRsIOStream::seek(TagLib::offset_t offset, Position p)
|
||||||
{
|
{
|
||||||
int32_t whence;
|
int32_t whence;
|
||||||
switch (p)
|
switch (p)
|
||||||
|
@ -121,35 +121,41 @@ namespace taglib_shim
|
||||||
rust_stream.seek(offset, whence);
|
rust_stream.seek(offset, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RustIOStream::clear()
|
void WrappedRsIOStream::clear()
|
||||||
{
|
{
|
||||||
truncate(0);
|
truncate(0);
|
||||||
seek(0);
|
seek(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RustIOStream::truncate(TagLib::offset_t length)
|
void WrappedRsIOStream::truncate(TagLib::offset_t length)
|
||||||
{
|
{
|
||||||
rust_stream.truncate(length);
|
rust_stream.truncate(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
TagLib::offset_t RustIOStream::tell() const
|
TagLib::offset_t WrappedRsIOStream::tell() const
|
||||||
{
|
{
|
||||||
return rust_stream.tell();
|
return rust_stream.tell();
|
||||||
}
|
}
|
||||||
|
|
||||||
TagLib::offset_t RustIOStream::length()
|
TagLib::offset_t WrappedRsIOStream::length()
|
||||||
{
|
{
|
||||||
return rust_stream.length();
|
return rust_stream.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RustIOStream::readOnly() const
|
bool WrappedRsIOStream::readOnly() const
|
||||||
{
|
{
|
||||||
return rust_stream.is_readonly();
|
return rust_stream.is_readonly();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RustIOStream::isOpen() const
|
bool WrappedRsIOStream::isOpen() const
|
||||||
{
|
{
|
||||||
return true; // If we have a stream, it's open
|
return true; // If we have a stream, it's open
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Factory function to create a new RustIOStream
|
||||||
|
std::unique_ptr<TagLib::IOStream> wrap_RsIOStream(RsIOStream& stream)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<TagLib::IOStream>(new WrappedRsIOStream(stream));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace taglib_shim
|
} // namespace taglib_shim
|
|
@ -7,39 +7,10 @@
|
||||||
#include "rust/cxx.h"
|
#include "rust/cxx.h"
|
||||||
|
|
||||||
// Forward declare the bridge type
|
// Forward declare the bridge type
|
||||||
struct BridgeStream;
|
struct RsIOStream;
|
||||||
|
|
||||||
namespace taglib_shim
|
namespace taglib_shim
|
||||||
{
|
{
|
||||||
|
|
||||||
// C++ implementation of TagLib::IOStream that delegates to Rust
|
|
||||||
class RustIOStream : public TagLib::IOStream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit RustIOStream(BridgeStream& stream);
|
|
||||||
~RustIOStream() override;
|
|
||||||
|
|
||||||
// TagLib::IOStream interface implementation
|
|
||||||
TagLib::FileName name() const override;
|
|
||||||
TagLib::ByteVector readBlock(size_t length) override;
|
|
||||||
void writeBlock(const TagLib::ByteVector &data) override;
|
|
||||||
void insert(const TagLib::ByteVector &data, TagLib::offset_t start = 0, size_t replace = 0) override;
|
|
||||||
void removeBlock(TagLib::offset_t start = 0, size_t length = 0) override;
|
|
||||||
void seek(TagLib::offset_t offset, Position p = Beginning) override;
|
|
||||||
void clear() override;
|
|
||||||
void truncate(TagLib::offset_t length) override;
|
|
||||||
TagLib::offset_t tell() const override;
|
|
||||||
TagLib::offset_t length() override;
|
|
||||||
bool readOnly() const override;
|
|
||||||
bool isOpen() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
BridgeStream& rust_stream;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Factory functions with external linkage
|
// Factory functions with external linkage
|
||||||
std::unique_ptr<RustIOStream> new_RustIOStream(BridgeStream& stream);
|
std::unique_ptr<TagLib::IOStream> wrap_RsIOStream(RsIOStream& stream);
|
||||||
|
|
||||||
std::unique_ptr<TagLib::FileRef> new_FileRef_from_stream(std::unique_ptr<RustIOStream> stream);
|
|
||||||
|
|
||||||
} // namespace taglib_shim
|
} // namespace taglib_shim
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::taglib::file::IOStream;
|
use crate::taglib::iostream::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;
|
||||||
|
@ -18,7 +18,7 @@ impl<'local, 'a> JInputStream<'local> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'local> IOStream for JInputStream<'local> {
|
impl<'local> IOStream for JInputStream<'local> {
|
||||||
fn name(&mut self) -> String {
|
fn name(&self) -> String {
|
||||||
// Call the Java name() method safely
|
// Call the Java name() method safely
|
||||||
let name = self
|
let name = self
|
||||||
.env
|
.env
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
|
use super::iostream::DynIOStream;
|
||||||
|
|
||||||
#[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 = "RsIOStream"]
|
||||||
type TIOStream<'a>;
|
type DynIOStream<'a>;
|
||||||
|
|
||||||
fn name(self: &mut TIOStream<'_>) -> String;
|
fn name(self: &mut DynIOStream<'_>) -> String;
|
||||||
fn read(self: &mut TIOStream<'_>, buffer: &mut [u8]) -> usize;
|
fn read(self: &mut DynIOStream<'_>, buffer: &mut [u8]) -> usize;
|
||||||
fn write(self: &mut TIOStream<'_>, data: &[u8]);
|
fn write(self: &mut DynIOStream<'_>, data: &[u8]);
|
||||||
fn seek(self: &mut TIOStream<'_>, offset: i64, whence: i32);
|
fn seek(self: &mut DynIOStream<'_>, offset: i64, whence: i32);
|
||||||
fn truncate(self: &mut TIOStream<'_>, length: i64);
|
fn truncate(self: &mut DynIOStream<'_>, length: i64);
|
||||||
fn tell(self: &mut TIOStream<'_>) -> i64;
|
fn tell(self: &mut DynIOStream<'_>) -> i64;
|
||||||
fn length(self: &mut TIOStream<'_>) -> i64;
|
fn length(self: &mut DynIOStream<'_>) -> i64;
|
||||||
fn is_readonly(self: &TIOStream<'_>) -> bool;
|
fn is_readonly(self: &mut DynIOStream<'_>) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[namespace = "taglib_shim"]
|
#[namespace = "taglib_shim"]
|
||||||
|
@ -22,12 +24,14 @@ mod bridge_impl {
|
||||||
include!("taglib/tstringlist.h");
|
include!("taglib/tstringlist.h");
|
||||||
include!("taglib/vorbisfile.h");
|
include!("taglib/vorbisfile.h");
|
||||||
include!("taglib/xiphcomment.h");
|
include!("taglib/xiphcomment.h");
|
||||||
|
include!("taglib/tiostream.h");
|
||||||
include!("shim/iostream_shim.hpp");
|
include!("shim/iostream_shim.hpp");
|
||||||
include!("shim/file_shim.hpp");
|
include!("shim/file_shim.hpp");
|
||||||
include!("shim/tk_shim.hpp");
|
include!("shim/tk_shim.hpp");
|
||||||
|
|
||||||
#[cxx_name = "RustIOStream"]
|
#[namespace = "TagLib"]
|
||||||
type RustIOStream;
|
#[cxx_name = "IOStream"]
|
||||||
|
type CPPIOStream;
|
||||||
|
|
||||||
#[namespace = "TagLib"]
|
#[namespace = "TagLib"]
|
||||||
#[cxx_name = "FileRef"]
|
#[cxx_name = "FileRef"]
|
||||||
|
@ -38,9 +42,9 @@ 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 TIOStream>) -> UniquePtr<RustIOStream>;
|
unsafe fn wrap_RsIOStream(stream: Pin<&mut DynIOStream>) -> UniquePtr<CPPIOStream>;
|
||||||
// Create a FileRef from an iostream
|
// Create a FileRef from an iostream
|
||||||
fn new_FileRef_from_stream(stream: UniquePtr<RustIOStream>) -> UniquePtr<TFileRef>;
|
unsafe fn new_FileRef(stream: *mut CPPIOStream) -> UniquePtr<TFileRef>;
|
||||||
|
|
||||||
#[namespace = "TagLib"]
|
#[namespace = "TagLib"]
|
||||||
#[cxx_name = "File"]
|
#[cxx_name = "File"]
|
||||||
|
@ -152,60 +156,3 @@ 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
use cxx::UniquePtr;
|
use cxx::UniquePtr;
|
||||||
use super::bridge::{self, TFileRef, TIOStream};
|
use super::bridge::{self, TFileRef};
|
||||||
|
use super::iostream::{IOStream, BridgedIOStream};
|
||||||
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 std::io::{Read, Write, Seek};
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
pub struct FileRef<'a> {
|
pub struct FileRef<'a> {
|
||||||
stream: Pin<Box<TIOStream<'a>>>,
|
stream: BridgedIOStream<'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 = TIOStream::new(stream);
|
let stream = BridgedIOStream::new(stream);
|
||||||
let iostream = unsafe { bridge::new_RustIOStream(bridge_stream.as_mut()) };
|
let cpp_stream = stream.cpp_stream().as_mut_ptr();
|
||||||
let file_ref = bridge::new_FileRef_from_stream(iostream);
|
let file_ref = unsafe { bridge::new_FileRef(cpp_stream) };
|
||||||
FileRef {
|
FileRef {
|
||||||
stream: bridge_stream,
|
stream,
|
||||||
file_ref
|
file_ref
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,8 +195,3 @@ impl <'a> Drop for FileRef<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IOStream: Read + Write + Seek {
|
|
||||||
fn name(&mut self) -> String;
|
|
||||||
fn is_readonly(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
93
musikr/src/main/jni/src/taglib/iostream.rs
Normal file
93
musikr/src/main/jni/src/taglib/iostream.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
|
||||||
|
use super::bridge::{self, CPPIOStream};
|
||||||
|
use std::io::{Read, Write, Seek, SeekFrom};
|
||||||
|
use std::pin::Pin;
|
||||||
|
use cxx::UniquePtr;
|
||||||
|
|
||||||
|
pub trait IOStream : Read + Write + Seek {
|
||||||
|
fn name(&self) -> String;
|
||||||
|
fn is_readonly(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(super) struct BridgedIOStream<'a> {
|
||||||
|
rs_stream: Pin<Box<DynIOStream<'a>>>,
|
||||||
|
cpp_stream: UniquePtr<CPPIOStream>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BridgedIOStream<'a> {
|
||||||
|
pub fn new<T : IOStream + 'a>(stream: T) -> Self {
|
||||||
|
let mut rs_stream = Box::pin(DynIOStream(Box::new(stream)));
|
||||||
|
let cpp_stream = unsafe { bridge::wrap_RsIOStream(rs_stream.as_mut()) };
|
||||||
|
BridgedIOStream {
|
||||||
|
rs_stream,
|
||||||
|
cpp_stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cpp_stream(&self) -> &UniquePtr<CPPIOStream> {
|
||||||
|
&self.cpp_stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for BridgedIOStream<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
// CPP stream references the rust stream, so it must be dropped first
|
||||||
|
std::ptr::drop_in_place(&mut self.cpp_stream);
|
||||||
|
std::ptr::drop_in_place(&mut self.rs_stream);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub(super) struct DynIOStream<'a>(Box<dyn IOStream + 'a>);
|
||||||
|
|
||||||
|
impl<'a> DynIOStream<'a> {
|
||||||
|
pub fn new<T: IOStream + 'a>(stream: T) -> Self {
|
||||||
|
DynIOStream(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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,3 +3,4 @@ mod bridge;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod tk;
|
pub mod tk;
|
||||||
pub mod xiph;
|
pub mod xiph;
|
||||||
|
pub mod iostream;
|
Loading…
Reference in a new issue