musikr: refined flac pic support
This commit is contained in:
parent
3dfcf0f67a
commit
f5de03dfee
13 changed files with 275 additions and 233 deletions
|
@ -119,6 +119,8 @@ fn main() {
|
|||
.file("shim/iostream_shim.cpp")
|
||||
.file("shim/file_shim.cpp")
|
||||
.file("shim/tk_shim.cpp")
|
||||
.file("shim/picture_shim.cpp")
|
||||
.file("shim/xiph_shim.cpp")
|
||||
.include(format!("taglib/pkg/{}/include", target))
|
||||
.include(".") // Add the current directory to include path
|
||||
.flag_if_supported("-std=c++14");
|
||||
|
@ -129,12 +131,6 @@ fn main() {
|
|||
builder.compile("taglib_cxx_bindings");
|
||||
|
||||
// Rebuild if shim files change
|
||||
println!("cargo:rerun-if-changed=shim/iostream_shim.hpp");
|
||||
println!("cargo:rerun-if-changed=shim/iostream_shim.cpp");
|
||||
println!("cargo:rerun-if-changed=shim/file_shim.hpp");
|
||||
println!("cargo:rerun-if-changed=shim/file_shim.cpp");
|
||||
println!("cargo:rerun-if-changed=shim/tk_shim.hpp");
|
||||
println!("cargo:rerun-if-changed=shim/tk_shim.cpp");
|
||||
println!("cargo:rerun-if-changed=src/taglib/ffi.rs");
|
||||
println!("cargo:rerun-if-changed=shim/");
|
||||
println!("cargo:rerun-if-changed=taglib/");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,23 @@
|
|||
#include "picture_shim.hpp"
|
||||
#include "taglib/flacfile.h"
|
||||
|
||||
namespace taglib_shim {
|
||||
std::unique_ptr<PictureList> XiphComment_pictureList(TagLib::Ogg::XiphComment& comment) {
|
||||
return std::make_unique<PictureList>(comment.pictureList());
|
||||
}
|
||||
|
||||
std::unique_ptr<PictureList> FLACFile_pictureList(TagLib::FLAC::File& file) {
|
||||
return std::make_unique<PictureList>(file.pictureList());
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<WrappedPicture>> PictureList_to_vector(const PictureList& list) {
|
||||
auto result = std::make_unique<std::vector<WrappedPicture>>();
|
||||
for (const auto* picture : list) {
|
||||
result->emplace_back(picture);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<TagLib::String> Picture_mimeType(const TagLib::FLAC::Picture& picture) {
|
||||
return std::make_unique<TagLib::String>(picture.mimeType());
|
||||
}
|
||||
|
|
|
@ -3,10 +3,24 @@
|
|||
#include "taglib/flacpicture.h"
|
||||
#include "taglib/tstring.h"
|
||||
#include "taglib/tbytevector.h"
|
||||
#include "tk_shim.hpp"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace taglib_shim {
|
||||
std::unique_ptr<TagLib::String> Picture_mimeType(const TagLib::FLAC::Picture& picture);
|
||||
std::unique_ptr<TagLib::String> Picture_description(const TagLib::FLAC::Picture& picture);
|
||||
using PictureList = TagLib::List<TagLib::FLAC::Picture *>;
|
||||
|
||||
class WrappedPicture {
|
||||
public:
|
||||
WrappedPicture(const TagLib::FLAC::Picture* picture) : picture(picture) {}
|
||||
const TagLib::FLAC::Picture* inner() const { return picture; }
|
||||
private:
|
||||
const TagLib::FLAC::Picture* picture;
|
||||
};
|
||||
std::unique_ptr<PictureList> FLACFile_pictureList(TagLib::FLAC::File& file);
|
||||
std::unique_ptr<PictureList> XiphComment_pictureList(TagLib::Ogg::XiphComment& comment);
|
||||
|
||||
std::unique_ptr<std::vector<WrappedPicture>> PictureList_to_vector(const PictureList& list);
|
||||
|
||||
std::unique_ptr<TagLib::ByteVector> Picture_data(const TagLib::FLAC::Picture& picture);
|
||||
}
|
|
@ -32,42 +32,4 @@ namespace taglib_shim
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<PictureRef>> FLACFile_pictureList_to_vector(TagLib::FLAC::File &file)
|
||||
{
|
||||
std::unique_ptr<std::vector<PictureRef>> result = std::make_unique<std::vector<PictureRef>>();
|
||||
const auto pictures = file.pictureList();
|
||||
for (const auto &picture : pictures)
|
||||
{
|
||||
result->push_back(PictureRef(picture));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<PictureRef>> XiphComment_pictureList_to_vector(TagLib::Ogg::XiphComment &comment)
|
||||
{
|
||||
std::unique_ptr<std::vector<PictureRef>> result = std::make_unique<std::vector<PictureRef>>();
|
||||
const auto pictures = comment.pictureList();
|
||||
for (const auto &picture : pictures)
|
||||
{
|
||||
result->push_back(PictureRef(picture));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
rust::String String_to_string(const TagLib::String &str)
|
||||
{
|
||||
return rust::String(str.to8Bit());
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<uint8_t>> ByteVector_to_bytes(const TagLib::ByteVector &data)
|
||||
{
|
||||
auto result = std::make_unique<std::vector<uint8_t>>();
|
||||
result->reserve(data.size());
|
||||
for (size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
result->push_back(static_cast<uint8_t>(data[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,17 +27,7 @@ namespace taglib_shim
|
|||
TagLib::StringList value_;
|
||||
};
|
||||
|
||||
struct PictureRef {
|
||||
PictureRef(const TagLib::FLAC::Picture* picture) : picture_(picture) {}
|
||||
const TagLib::FLAC::Picture* get() const { return picture_; }
|
||||
private:
|
||||
const TagLib::FLAC::Picture* picture_;
|
||||
};
|
||||
|
||||
std::unique_ptr<std::vector<Property>> SimplePropertyMap_to_vector(const TagLib::SimplePropertyMap &map);
|
||||
std::unique_ptr<std::vector<TagLib::String>> StringList_to_vector(const TagLib::StringList &list);
|
||||
std::unique_ptr<std::vector<PictureRef>> FLACFile_pictureList_to_vector(TagLib::FLAC::File &file);
|
||||
std::unique_ptr<std::vector<PictureRef>> XiphComment_pictureList_to_vector(TagLib::Ogg::XiphComment &comment);
|
||||
rust::String String_to_string(const TagLib::String &str);
|
||||
std::unique_ptr<std::vector<uint8_t>> ByteVector_to_bytes(const TagLib::ByteVector &data);
|
||||
}
|
26
musikr/src/main/jni/shim/xiph_shim.cpp
Normal file
26
musikr/src/main/jni/shim/xiph_shim.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "xiph_shim.hpp"
|
||||
|
||||
namespace taglib_shim
|
||||
{
|
||||
FieldListEntry::FieldListEntry(TagLib::String key, TagLib::StringList value) : key_(key), value_(value) {}
|
||||
|
||||
const TagLib::String &FieldListEntry::key() const
|
||||
{
|
||||
return key_;
|
||||
}
|
||||
|
||||
const TagLib::StringList &FieldListEntry::value() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<FieldListEntry>> FieldListMap_to_entries(const TagLib::SimplePropertyMap &map)
|
||||
{
|
||||
std::unique_ptr<std::vector<FieldListEntry>> result = std::make_unique<std::vector<FieldListEntry>>();
|
||||
for (const auto &pair : map)
|
||||
{
|
||||
result->push_back(FieldListEntry(pair.first, pair.second));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
22
musikr/src/main/jni/shim/xiph_shim.hpp
Normal file
22
musikr/src/main/jni/shim/xiph_shim.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "taglib/tpropertymap.h"
|
||||
#include "taglib/xiphcomment.h"
|
||||
|
||||
namespace taglib_shim
|
||||
{
|
||||
using FieldListMap = TagLib::SimplePropertyMap;
|
||||
|
||||
struct FieldListEntry
|
||||
{
|
||||
FieldListEntry(TagLib::String key, TagLib::StringList value);
|
||||
const TagLib::String &key() const;
|
||||
const TagLib::StringList &value() const;
|
||||
|
||||
private:
|
||||
TagLib::String key_;
|
||||
TagLib::StringList value_;
|
||||
};
|
||||
|
||||
|
||||
std::unique_ptr<std::vector<FieldListEntry>> FieldListMap_to_entries(const FieldListMap &map);
|
||||
std::unique_ptr<std::vector<TagLib::String>> StringList_to_vector(const TagLib::StringList &list);
|
||||
}
|
|
@ -31,12 +31,13 @@ mod bridge_impl {
|
|||
include!("shim/file_shim.hpp");
|
||||
include!("shim/tk_shim.hpp");
|
||||
include!("shim/picture_shim.hpp");
|
||||
include!("shim/xiph_shim.hpp");
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "IOStream"]
|
||||
type CPPIOStream;
|
||||
// Create a RustIOStream from a BridgeStream
|
||||
unsafe fn wrap_RsIOStream(stream: Pin<&mut DynIOStream>) -> UniquePtr<CPPIOStream>;
|
||||
fn wrap_RsIOStream(stream: Pin<&mut DynIOStream>) -> UniquePtr<CPPIOStream>;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "FileRef"]
|
||||
|
@ -65,53 +66,68 @@ mod bridge_impl {
|
|||
#[cxx_name = "sampleRate"]
|
||||
fn sampleRate(self: Pin<&CppAudioProperties>) -> i32;
|
||||
#[cxx_name = "channels"]
|
||||
fn channels(self: Pin<&CppAudioProperties>) -> i32;
|
||||
fn channels(self: Pin<&CppAudioProperties>) -> i32;
|
||||
|
||||
#[namespace = "TagLib::FLAC"]
|
||||
#[cxx_name = "Picture"]
|
||||
type CPPFLACPicture;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn Picture_mimeType(picture: &CPPFLACPicture) -> UniquePtr<CPPString>;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn Picture_description(picture: &CPPFLACPicture) -> UniquePtr<CPPString>;
|
||||
#[cxx_name = "width"]
|
||||
fn width(self: Pin<&CPPFLACPicture>) -> i32;
|
||||
#[cxx_name = "height"]
|
||||
fn height(self: Pin<&CPPFLACPicture>) -> i32;
|
||||
#[cxx_name = "colorDepth"]
|
||||
fn colorDepth(self: Pin<&CPPFLACPicture>) -> i32;
|
||||
#[cxx_name = "numColors"]
|
||||
fn numColors(self: Pin<&CPPFLACPicture>) -> i32;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn Picture_data(picture: &CPPFLACPicture) -> UniquePtr<CPPByteVector>;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "ByteVector"]
|
||||
type CPPByteVector;
|
||||
fn Picture_data(picture: Pin<&CPPFLACPicture>) -> UniquePtr<CPPByteVector>;
|
||||
|
||||
#[namespace = "TagLib::Ogg"]
|
||||
#[cxx_name = "XiphComment"]
|
||||
type CPPXiphComment;
|
||||
#[cxx_name = "fieldListMap"]
|
||||
fn fieldListMap(self: Pin<&CPPXiphComment>) -> &CPPSimplePropertyMap;
|
||||
fn fieldListMap(self: Pin<&CPPXiphComment>) -> &CPPFieldListMap;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "SimplePropertyMap"]
|
||||
type CPPFieldListMap;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn FieldListMap_to_entries(
|
||||
field_list_map: Pin<&CPPFieldListMap>,
|
||||
) -> UniquePtr<CxxVector<CPPFieldListEntry>>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
#[cxx_name = "FieldListEntry"]
|
||||
type CPPFieldListEntry;
|
||||
#[cxx_name = "key"]
|
||||
fn key(self: Pin<&CPPFieldListEntry>) -> &CPPString;
|
||||
#[cxx_name = "value"]
|
||||
fn value(self: Pin<&CPPFieldListEntry>) -> &CPPStringList;
|
||||
|
||||
#[namespace = "TagLib::Ogg::Vorbis"]
|
||||
#[cxx_name = "File"]
|
||||
type CPPVorbisFile;
|
||||
#[cxx_name = "tag"]
|
||||
unsafe fn vorbisTag(self: Pin<&CPPVorbisFile>) -> *mut CPPXiphComment;
|
||||
fn vorbisTag(self: Pin<&CPPVorbisFile>) -> *mut CPPXiphComment;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn XiphComment_pictureList(comment: Pin<&mut CPPXiphComment>) -> UniquePtr<CPPPictureList>;
|
||||
|
||||
#[namespace = "TagLib::Ogg::Opus"]
|
||||
#[cxx_name = "File"]
|
||||
type CPPOpusFile;
|
||||
#[cxx_name = "tag"]
|
||||
unsafe fn opusTag(self: Pin<&CPPOpusFile>) -> *mut CPPXiphComment;
|
||||
fn opusTag(self: Pin<&CPPOpusFile>) -> *mut CPPXiphComment;
|
||||
|
||||
#[namespace = "TagLib::FLAC"]
|
||||
#[cxx_name = "File"]
|
||||
type CPPFLACFile;
|
||||
#[cxx_name = "xiphComment"]
|
||||
unsafe fn xiphComment(self: Pin<&mut CPPFLACFile>, create: bool) -> *mut CPPXiphComment;
|
||||
fn xiphComment(self: Pin<&mut CPPFLACFile>, create: bool) -> *mut CPPXiphComment;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn FLACFile_pictureList(file: Pin<&mut CPPFLACFile>) -> UniquePtr<CPPPictureList>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
#[cxx_name = "PictureList"]
|
||||
type CPPPictureList;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn PictureList_to_vector(list: Pin<&CPPPictureList>) -> UniquePtr<CxxVector<CPPWrappedPicture>>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
#[cxx_name = "WrappedPicture"]
|
||||
type CPPWrappedPicture;
|
||||
fn inner(self: &CPPWrappedPicture) -> *const CPPFLACPicture;
|
||||
|
||||
#[namespace = "TagLib::MPEG"]
|
||||
#[cxx_name = "File"]
|
||||
|
@ -125,14 +141,6 @@ mod bridge_impl {
|
|||
#[cxx_name = "File"]
|
||||
type CPPWAVFile;
|
||||
|
||||
// #[namespace = "TagLib::WavPack"]
|
||||
// #[cxx_name = "File"]
|
||||
// type WavPackFile;
|
||||
|
||||
// #[namespace = "TagLib::APE"]
|
||||
// #[cxx_name = "File"]
|
||||
// type APEFile;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asVorbis(file: *mut CPPFile) -> *mut CPPVorbisFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
|
@ -146,47 +154,23 @@ mod bridge_impl {
|
|||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asWAV(file: *mut CPPFile) -> *mut CPPWAVFile;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "SimplePropertyMap"]
|
||||
type CPPSimplePropertyMap;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn SimplePropertyMap_to_vector(
|
||||
field_list_map: Pin<&CPPSimplePropertyMap>,
|
||||
) -> UniquePtr<CxxVector<CPPProperty>>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
#[cxx_name = "Property"]
|
||||
type CPPProperty;
|
||||
#[cxx_name = "key"]
|
||||
fn key(self: Pin<&CPPProperty>) -> &CPPString;
|
||||
#[cxx_name = "value"]
|
||||
unsafe fn value(self: Pin<&CPPProperty>) -> &CPPStringList;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "String"]
|
||||
type CPPString;
|
||||
#[cxx_name = "toCString"]
|
||||
unsafe fn thisToCString(self: Pin<&CPPString>, unicode: bool) -> *const c_char;
|
||||
fn toCString(self: Pin<&CPPString>, unicode: bool) -> *const c_char;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "StringList"]
|
||||
type CPPStringList;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn StringList_to_vector(string_list: Pin<&CPPStringList>) -> UniquePtr<CxxVector<CPPString>>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
type PictureRef;
|
||||
fn get(self: &PictureRef) -> *const CPPFLACPicture;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
fn FLACFile_pictureList_to_vector(file: Pin<&mut CPPFLACFile>) -> UniquePtr<CxxVector<PictureRef>>;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn XiphComment_pictureList_to_vector(comment: Pin<&mut CPPXiphComment>) -> UniquePtr<CxxVector<PictureRef>>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
fn String_to_string(str: &CPPString) -> String;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn ByteVector_to_bytes(data: &CPPByteVector) -> UniquePtr<CxxVector<u8>>;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "ByteVector"]
|
||||
type CPPByteVector;
|
||||
fn size(self: Pin<&CPPByteVector>) -> u32;
|
||||
fn data(self: Pin<&CPPByteVector>) -> *const c_char;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
pub use super::bridge::CPPFLACFile;
|
||||
pub use super::bridge::CPPFLACPicture;
|
||||
pub use super::xiph::XiphComment;
|
||||
use super::bridge::{FLACFile_pictureList_to_vector, String_to_string, ByteVector_to_bytes, Picture_mimeType, Picture_description, Picture_data};
|
||||
use super::bridge::{CPPPictureList, PictureList_to_vector, FLACFile_pictureList, Picture_data};
|
||||
use super::tk::ByteVector;
|
||||
use std::marker::PhantomData;
|
||||
use cxx::UniquePtr;
|
||||
use std::pin::Pin;
|
||||
|
||||
pub struct FLACFile<'a> {
|
||||
|
@ -15,15 +18,7 @@ impl<'a> FLACFile<'a> {
|
|||
|
||||
pub fn xiph_comments(&mut self) -> Option<XiphComment> {
|
||||
let this = self.this.as_mut();
|
||||
let tag = unsafe {
|
||||
// SAFETY:
|
||||
// - This pin is only used in this unsafe scope.
|
||||
// - The pin is used as a C++ this pointer in the ffi call, which does
|
||||
// not change address by C++ semantics.
|
||||
// - The value is a pointer that does not depend on the address of self.
|
||||
// SAFETY: This is a C++ FFI function ensured to call correctly.
|
||||
this.xiphComment(false)
|
||||
};
|
||||
let tag = this.xiphComment(false);
|
||||
let tag_ref = unsafe {
|
||||
// SAFETY: This pointer is a valid type, and can only used and accessed
|
||||
// via this function and thus cannot be mutated, satisfying the aliasing rules.
|
||||
|
@ -33,11 +28,35 @@ impl<'a> FLACFile<'a> {
|
|||
tag_pin.map(|tag| XiphComment::new(tag))
|
||||
}
|
||||
|
||||
pub fn picture_list(&mut self) -> Vec<Picture<'a>> {
|
||||
let pictures = FLACFile_pictureList_to_vector(self.this.as_mut());
|
||||
pub fn picture_list(&mut self) -> PictureList {
|
||||
let pictures = FLACFile_pictureList(self.this.as_mut());
|
||||
PictureList::new(pictures)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PictureList<'a> {
|
||||
// PictureList is implicitly tied to the lifetime of the parent that owns it,
|
||||
// so we need to track that lifetime.
|
||||
_data: PhantomData<&'a CPPFLACPicture>,
|
||||
this: UniquePtr<CPPPictureList>,
|
||||
}
|
||||
|
||||
impl<'a> PictureList<'a> {
|
||||
pub(super) fn new(this: UniquePtr<CPPPictureList>) -> Self {
|
||||
Self { _data: PhantomData, this }
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<Picture> {
|
||||
let pictures = PictureList_to_vector(unsafe {
|
||||
// SAFETY: This pin is only used in this unsafe scope.
|
||||
// The pin is used as a C++ this pointer in the ffi call, which does
|
||||
// not change address by C++ semantics.
|
||||
Pin::new_unchecked(self.this.as_ref().unwrap())
|
||||
});
|
||||
|
||||
let mut result = Vec::new();
|
||||
for picture_ref in pictures.iter() {
|
||||
let picture_ptr = picture_ref.get();
|
||||
let picture_ptr = picture_ref.inner();
|
||||
let picture_ref = unsafe {
|
||||
// SAFETY: This pointer is a valid type, and can only used and accessed
|
||||
// via this function and thus cannot be mutated, satisfying the aliasing rules.
|
||||
|
@ -59,31 +78,8 @@ impl<'a> Picture<'a> {
|
|||
Self { this }
|
||||
}
|
||||
|
||||
pub fn mime_type(&self) -> String {
|
||||
String_to_string(Picture_mimeType(self.this.get_ref()).as_ref().unwrap())
|
||||
}
|
||||
|
||||
pub fn description(&self) -> String {
|
||||
String_to_string(Picture_description(self.this.get_ref()).as_ref().unwrap())
|
||||
}
|
||||
|
||||
pub fn width(&self) -> i32 {
|
||||
self.this.width()
|
||||
}
|
||||
|
||||
pub fn height(&self) -> i32 {
|
||||
self.this.height()
|
||||
}
|
||||
|
||||
pub fn color_depth(&self) -> i32 {
|
||||
self.this.colorDepth()
|
||||
}
|
||||
|
||||
pub fn num_colors(&self) -> i32 {
|
||||
self.this.numColors()
|
||||
}
|
||||
|
||||
pub fn data(&self) -> Vec<u8> {
|
||||
ByteVector_to_bytes(Picture_data(self.this.get_ref()).as_ref().unwrap()).iter().map(|b| *b).collect()
|
||||
pub fn data(&self) -> ByteVector<'a> {
|
||||
let data = Picture_data(self.this);
|
||||
ByteVector::new(data)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ pub(super) struct BridgedIOStream<'a> {
|
|||
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()) };
|
||||
let cpp_stream = bridge::wrap_RsIOStream(rs_stream.as_mut());
|
||||
BridgedIOStream {
|
||||
rs_stream,
|
||||
cpp_stream
|
||||
|
|
|
@ -13,14 +13,7 @@ impl<'a> VorbisFile<'a> {
|
|||
|
||||
pub fn xiph_comments(&self) -> Option<XiphComment> {
|
||||
let this = self.this.as_ref();
|
||||
let tag = unsafe {
|
||||
// SAFETY:
|
||||
// - This pin is only used in this unsafe scope.
|
||||
// - The pin is used as a C++ this pointer in the ffi call, which does
|
||||
// not change address by C++ semantics.
|
||||
// - The value is a pointer that does not depend on the address of self.
|
||||
this.vorbisTag()
|
||||
};
|
||||
let tag = this.vorbisTag();
|
||||
let tag_ref = unsafe {
|
||||
// SAFETY: This pointer is a valid type, and can only used and accessed
|
||||
// via this function and thus cannot be mutated, satisfying the aliasing rules.
|
||||
|
|
|
@ -1,51 +1,22 @@
|
|||
use std::collections::HashMap;
|
||||
use super::bridge::{self, CPPByteVector, CPPString, CPPStringList};
|
||||
use cxx::UniquePtr;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::{ffi::CStr, string::ToString};
|
||||
use super::bridge::{self, CPPSimplePropertyMap, CPPString, CPPStringList};
|
||||
|
||||
pub struct SimplePropertyMap<'a> {
|
||||
this: Pin<&'a CPPSimplePropertyMap>,
|
||||
pub struct String<'a> {
|
||||
this: Pin<&'a CPPString>,
|
||||
}
|
||||
|
||||
impl<'a> SimplePropertyMap<'a> {
|
||||
pub(super) fn new(this: Pin<&'a CPPSimplePropertyMap>) -> Self {
|
||||
impl<'a> String<'a> {
|
||||
pub(super) fn new(this: Pin<&'a CPPString>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SimplePropertyMap<'a> {
|
||||
pub fn to_hashmap(&self) -> HashMap<String, Vec<String>> {
|
||||
let cxx_vec = bridge::SimplePropertyMap_to_vector(self.this);
|
||||
cxx_vec
|
||||
.iter()
|
||||
.map(|property| unsafe {
|
||||
// SAFETY:
|
||||
// - This pin is only used in this unsafe scope.
|
||||
// - The pin is used as a C++ this pointer in the ffi call, which does
|
||||
// not change address by C++ semantics.
|
||||
// - The values returned are copied and thus not dependent on the address
|
||||
// of self.
|
||||
let property_pin = Pin::new_unchecked(property);
|
||||
let key = property_pin.key().to_string();
|
||||
let value = property_pin.value().to_vec();
|
||||
(key, value)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for CPPString {
|
||||
fn to_string(&self) -> String {
|
||||
let c_str = unsafe {
|
||||
// SAFETY:
|
||||
// - This pin is only used in this unsafe scope.
|
||||
// - The pin is used as a C++ this pointer in the ffi call, which does
|
||||
// not change address by C++ semantics.
|
||||
// - The value returned are pointers and thus not dependent on the address
|
||||
// of self.
|
||||
let this: Pin<&CPPString> = Pin::new_unchecked(self);
|
||||
this.thisToCString(true)
|
||||
};
|
||||
impl<'a> ToString for String<'a> {
|
||||
fn to_string(&self) -> std::string::String {
|
||||
let c_str = self.this.toCString(true);
|
||||
unsafe {
|
||||
// SAFETY:
|
||||
// - This is a C-string returned by a C++ method guaranteed to have
|
||||
|
@ -63,18 +34,64 @@ impl ToString for CPPString {
|
|||
}
|
||||
}
|
||||
|
||||
impl CPPStringList {
|
||||
pub fn to_vec(&self) -> Vec<String> {
|
||||
let cxx_values = unsafe {
|
||||
pub struct StringList<'a> {
|
||||
this: Pin<&'a CPPStringList>,
|
||||
}
|
||||
|
||||
impl<'a> StringList<'a> {
|
||||
pub(super) fn new(this: Pin<&'a CPPStringList>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<std::string::String> {
|
||||
let cxx_values = bridge::StringList_to_vector(self.this);
|
||||
cxx_values
|
||||
.iter()
|
||||
.map(|value| {
|
||||
let this = unsafe {
|
||||
Pin::new_unchecked(value)
|
||||
};
|
||||
String::new(this).to_string()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ByteVector<'a> {
|
||||
// ByteVector is implicitly tied to the lifetime of the parent that owns it,
|
||||
// so we need to track that lifetime. Only reason why it's a UniquePtr is because
|
||||
// we can't marshal over ownership of the ByteVector by itself over cxx.
|
||||
_data: PhantomData<&'a CPPByteVector>,
|
||||
this: UniquePtr<CPPByteVector>,
|
||||
}
|
||||
|
||||
impl<'a> ByteVector<'a> {
|
||||
pub(super) fn new(this: UniquePtr<CPPByteVector>) -> Self {
|
||||
Self {
|
||||
_data: PhantomData,
|
||||
this,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
let this_ref = self.this.as_ref().unwrap();
|
||||
let this = unsafe {
|
||||
// SAFETY:
|
||||
// - This pin is only used in this unsafe scope.
|
||||
// - The pin is used as a C++ this pointer in the ffi call, which does
|
||||
// not change address by C++ semantics.
|
||||
// - The value returned is a unique ptr to a copied vector that is not
|
||||
// dependent on the address of self.
|
||||
let this = Pin::new_unchecked(self);
|
||||
bridge::StringList_to_vector(this)
|
||||
Pin::new_unchecked(this_ref)
|
||||
};
|
||||
cxx_values.iter().map(|value| value.to_string()).collect()
|
||||
let size = this.size().try_into().unwrap();
|
||||
let data = this.data();
|
||||
// Re-cast to u8
|
||||
let data: *const u8 = data as *const u8;
|
||||
unsafe {
|
||||
// SAFETY:
|
||||
// - data points to a valid buffer of size 'size' owned by the C++ ByteVector
|
||||
// - we're creating a new Vec and copying the data, not taking ownership
|
||||
// - the source data won't be modified while we're reading from it
|
||||
std::slice::from_raw_parts(data, size).to_vec()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
pub use super::bridge::CPPXiphComment;
|
||||
pub use super::flac::Picture;
|
||||
use super::bridge::XiphComment_pictureList_to_vector;
|
||||
use super::tk::SimplePropertyMap;
|
||||
pub use super::flac::PictureList;
|
||||
use super::bridge::{CPPFieldListMap, FieldListMap_to_entries, XiphComment_pictureList};
|
||||
use super::tk;
|
||||
use std::pin::Pin;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct XiphComment<'a> {
|
||||
this: Pin<&'a mut CPPXiphComment>
|
||||
|
@ -13,25 +14,49 @@ impl<'a> XiphComment<'a> {
|
|||
Self { this }
|
||||
}
|
||||
|
||||
pub fn field_list_map(&'a self) -> SimplePropertyMap<'a> {
|
||||
pub fn field_list_map(&'a self) -> FieldListMap<'a> {
|
||||
let map = self.this.as_ref().fieldListMap();
|
||||
let map_pin = unsafe { Pin::new_unchecked(map) };
|
||||
SimplePropertyMap::new(map_pin)
|
||||
FieldListMap::new(map_pin)
|
||||
}
|
||||
|
||||
pub fn picture_list(&mut self) -> Vec<Picture<'a>> {
|
||||
let pictures = XiphComment_pictureList_to_vector(self.this.as_mut());
|
||||
let mut result = Vec::new();
|
||||
for picture_ref in pictures.iter() {
|
||||
let picture_ptr = picture_ref.get();
|
||||
let picture_ref = unsafe {
|
||||
// SAFETY: This pointer is a valid type, and can only used and accessed
|
||||
// via this function and thus cannot be mutated, satisfying the aliasing rules.
|
||||
picture_ptr.as_ref().unwrap()
|
||||
};
|
||||
let picture_pin = unsafe { Pin::new_unchecked(picture_ref) };
|
||||
result.push(Picture::new(picture_pin));
|
||||
}
|
||||
result
|
||||
pub fn picture_list(&mut self) -> PictureList<'a> {
|
||||
let pictures = XiphComment_pictureList(self.this.as_mut());
|
||||
PictureList::new(pictures)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldListMap<'a> {
|
||||
this: Pin<&'a CPPFieldListMap>,
|
||||
}
|
||||
|
||||
impl<'a> FieldListMap<'a> {
|
||||
pub(super) fn new(this: Pin<&'a CPPFieldListMap>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FieldListMap<'a> {
|
||||
pub fn to_hashmap(&self) -> HashMap<String, Vec<String>> {
|
||||
let cxx_vec = FieldListMap_to_entries(self.this);
|
||||
cxx_vec
|
||||
.iter()
|
||||
.map(|property| {
|
||||
// SAFETY:
|
||||
// - This pin is only used in this unsafe scope.
|
||||
// - The pin is used as a C++ this pointer in the ffi call, which does
|
||||
// not change address by C++ semantics.
|
||||
// - The values returned are copied and thus not dependent on the address
|
||||
// of self.
|
||||
let property_pin = unsafe { Pin::new_unchecked(property) };
|
||||
let key_ref = property_pin.key();
|
||||
let key_pin = unsafe { Pin::new_unchecked(key_ref) };
|
||||
let key = tk::String::new(key_pin).to_string();
|
||||
let value_ref = property_pin.value();
|
||||
let value_pin = unsafe { Pin::new_unchecked(value_ref) };
|
||||
let value = tk::StringList::new(value_pin).to_vec();
|
||||
(key, value)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue