musikr: introduce this abstraction
Gets rid of a lot of the duplicate pin stuff
This commit is contained in:
parent
c8d645c282
commit
0cb1b3a309
11 changed files with 260 additions and 204 deletions
|
@ -1,28 +1,29 @@
|
||||||
use super::bridge::CppAudioProperties;
|
use super::bridge::CppAudioProperties;
|
||||||
|
use super::this::{RefThis, This};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
pub struct AudioProperties<'file_ref> {
|
pub struct AudioProperties<'file_ref> {
|
||||||
this: Pin<&'file_ref CppAudioProperties>,
|
this: RefThis<'file_ref, CppAudioProperties>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> AudioProperties<'file_ref> {
|
impl<'file_ref> AudioProperties<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref CppAudioProperties>) -> Self {
|
pub(super) fn new(this: RefThis<'file_ref, CppAudioProperties>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn length_in_milliseconds(&self) -> i32 {
|
pub fn length_in_milliseconds(&self) -> i32 {
|
||||||
self.this.as_ref().lengthInMilliseconds()
|
self.this.pin().lengthInMilliseconds()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitrate(&self) -> i32 {
|
pub fn bitrate(&self) -> i32 {
|
||||||
self.this.as_ref().bitrate()
|
self.this.pin().bitrate()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sample_rate(&self) -> i32 {
|
pub fn sample_rate(&self) -> i32 {
|
||||||
self.this.as_ref().sampleRate()
|
self.this.pin().sampleRate()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn channels(&self) -> i32 {
|
pub fn channels(&self) -> i32 {
|
||||||
self.this.as_ref().channels()
|
self.this.pin().channels()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,20 @@ use super::id3v2::ID3v2Tag;
|
||||||
use super::mpeg::MPEGFile;
|
use super::mpeg::MPEGFile;
|
||||||
use super::ogg::OpusFile;
|
use super::ogg::OpusFile;
|
||||||
use super::ogg::VorbisFile;
|
use super::ogg::VorbisFile;
|
||||||
|
use super::this::{RefThisMut, RefThis, This, ThisMut};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
pub struct File<'file_ref> {
|
pub struct File<'file_ref> {
|
||||||
this: Pin<&'file_ref mut CPPFile>,
|
this: RefThisMut<'file_ref, CPPFile>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> File<'file_ref> {
|
impl<'file_ref> File<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref mut CPPFile>) -> Self {
|
pub(super) fn new(this: RefThisMut<'file_ref, CPPFile>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn audio_properties(&self) -> Option<AudioProperties<'file_ref>> {
|
pub fn audio_properties(&self) -> Option<AudioProperties<'file_ref>> {
|
||||||
let props_ptr = self.this.as_ref().audioProperties();
|
let props_ptr = self.this.pin().audioProperties();
|
||||||
let props_ref = unsafe {
|
let props_ref = unsafe {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - This points to a C++ FFI type ensured to be aligned by cxx's codegen.
|
// - This points to a C++ FFI type ensured to be aligned by cxx's codegen.
|
||||||
|
@ -27,8 +28,8 @@ impl<'file_ref> File<'file_ref> {
|
||||||
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
||||||
props_ptr.as_ref()
|
props_ptr.as_ref()
|
||||||
};
|
};
|
||||||
let props_pin = props_ref.map(|props| unsafe { Pin::new_unchecked(props) });
|
let props_this = props_ref.map(|props| unsafe { RefThis::new(props) });
|
||||||
props_pin.map(|props| AudioProperties::new(props))
|
props_this.map(|this| AudioProperties::new(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_opus(&mut self) -> Option<OpusFile<'file_ref>> {
|
pub fn as_opus(&mut self) -> Option<OpusFile<'file_ref>> {
|
||||||
|
@ -37,7 +38,7 @@ impl<'file_ref> File<'file_ref> {
|
||||||
// This FFI function will be a simple C++ dynamic_cast, which checks if
|
// This FFI function will be a simple C++ dynamic_cast, which checks if
|
||||||
// the file can be cased down to an opus file. If the cast fails, a null
|
// the file can be cased down to an opus file. If the cast fails, a null
|
||||||
// pointer is returned, which will be handled by as_ref's null checking.
|
// pointer is returned, which will be handled by as_ref's null checking.
|
||||||
bridge::File_asOpus(self.this.as_mut().get_unchecked_mut() as *mut CPPFile)
|
bridge::File_asOpus(self.this.ptr_mut() as *mut CPPFile)
|
||||||
};
|
};
|
||||||
let opus_ref = unsafe {
|
let opus_ref = unsafe {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
|
@ -48,8 +49,8 @@ impl<'file_ref> File<'file_ref> {
|
||||||
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
||||||
opus_file.as_mut()
|
opus_file.as_mut()
|
||||||
};
|
};
|
||||||
let opus_pin = opus_ref.map(|opus| unsafe { Pin::new_unchecked(opus) });
|
let opus_this = opus_ref.map(|opus| unsafe { RefThisMut::new(opus) });
|
||||||
opus_pin.map(|opus| OpusFile::new(opus))
|
opus_this.map(|this| OpusFile::new(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_vorbis(&mut self) -> Option<VorbisFile<'file_ref>> {
|
pub fn as_vorbis(&mut self) -> Option<VorbisFile<'file_ref>> {
|
||||||
|
@ -58,7 +59,7 @@ impl<'file_ref> File<'file_ref> {
|
||||||
// This FFI function will be a simple C++ dynamic_cast, which checks if
|
// This FFI function will be a simple C++ dynamic_cast, which checks if
|
||||||
// the file can be cased down to an opus file. If the cast fails, a null
|
// the file can be cased down to an opus file. If the cast fails, a null
|
||||||
// pointer is returned, which will be handled by as_ref's null checking.
|
// pointer is returned, which will be handled by as_ref's null checking.
|
||||||
bridge::File_asVorbis(self.this.as_mut().get_unchecked_mut() as *mut CPPFile)
|
bridge::File_asVorbis(self.this.ptr_mut() as *mut CPPFile)
|
||||||
};
|
};
|
||||||
let vorbis_ref = unsafe {
|
let vorbis_ref = unsafe {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
|
@ -69,8 +70,8 @@ impl<'file_ref> File<'file_ref> {
|
||||||
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
||||||
vorbis_file.as_mut()
|
vorbis_file.as_mut()
|
||||||
};
|
};
|
||||||
let vorbis_pin = vorbis_ref.map(|vorbis| unsafe { Pin::new_unchecked(vorbis) });
|
let vorbis_this = vorbis_ref.map(|vorbis| unsafe { RefThisMut::new(vorbis) });
|
||||||
vorbis_pin.map(|vorbis| VorbisFile::new(vorbis))
|
vorbis_this.map(|this| VorbisFile::new(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_flac(&mut self) -> Option<FLACFile<'file_ref>> {
|
pub fn as_flac(&mut self) -> Option<FLACFile<'file_ref>> {
|
||||||
|
@ -79,7 +80,7 @@ impl<'file_ref> File<'file_ref> {
|
||||||
// This FFI function will be a simple C++ dynamic_cast, which checks if
|
// This FFI function will be a simple C++ dynamic_cast, which checks if
|
||||||
// the file can be cased down to an opus file. If the cast fails, a null
|
// the file can be cased down to an opus file. If the cast fails, a null
|
||||||
// pointer is returned, which will be handled by as_ref's null checking.
|
// pointer is returned, which will be handled by as_ref's null checking.
|
||||||
bridge::File_asFLAC(self.this.as_mut().get_unchecked_mut() as *mut CPPFile)
|
bridge::File_asFLAC(self.this.ptr_mut() as *mut CPPFile)
|
||||||
};
|
};
|
||||||
let flac_ref = unsafe {
|
let flac_ref = unsafe {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
|
@ -90,8 +91,8 @@ impl<'file_ref> File<'file_ref> {
|
||||||
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
||||||
flac_file.as_mut()
|
flac_file.as_mut()
|
||||||
};
|
};
|
||||||
let flac_pin = flac_ref.map(|flac| unsafe { Pin::new_unchecked(flac) });
|
let flac_this = flac_ref.map(|flac| unsafe { RefThisMut::new(flac) });
|
||||||
flac_pin.map(|flac| FLACFile::new(flac))
|
flac_this.map(|this| FLACFile::new(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_mpeg(&mut self) -> Option<MPEGFile<'file_ref>> {
|
pub fn as_mpeg(&mut self) -> Option<MPEGFile<'file_ref>> {
|
||||||
|
@ -100,7 +101,7 @@ impl<'file_ref> File<'file_ref> {
|
||||||
// This FFI function will be a simple C++ dynamic_cast, which checks if
|
// This FFI function will be a simple C++ dynamic_cast, which checks if
|
||||||
// the file can be cased down to an MPEG file. If the cast fails, a null
|
// the file can be cased down to an MPEG file. If the cast fails, a null
|
||||||
// pointer is returned, which will be handled by as_ref's null checking.
|
// pointer is returned, which will be handled by as_ref's null checking.
|
||||||
bridge::File_asMPEG(self.this.as_mut().get_unchecked_mut() as *mut CPPFile)
|
bridge::File_asMPEG(self.this.ptr_mut() as *mut CPPFile)
|
||||||
};
|
};
|
||||||
let mpeg_ref = unsafe {
|
let mpeg_ref = unsafe {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
|
@ -111,7 +112,7 @@ impl<'file_ref> File<'file_ref> {
|
||||||
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
||||||
mpeg_file.as_mut()
|
mpeg_file.as_mut()
|
||||||
};
|
};
|
||||||
let mpeg_pin = mpeg_ref.map(|mpeg| unsafe { Pin::new_unchecked(mpeg) });
|
let mpeg_this = mpeg_ref.map(|mpeg| unsafe { RefThisMut::new(mpeg) });
|
||||||
mpeg_pin.map(|mpeg| MPEGFile::new(mpeg))
|
mpeg_this.map(|this| MPEGFile::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::bridge::{self, CPPFileRef};
|
use super::bridge::{self, CPPFileRef};
|
||||||
use super::file::File;
|
use super::file::File;
|
||||||
use super::iostream::{BridgedIOStream, IOStream};
|
use super::iostream::{BridgedIOStream, IOStream};
|
||||||
|
use super::this::RefThisMut;
|
||||||
use cxx::UniquePtr;
|
use cxx::UniquePtr;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
@ -47,8 +48,8 @@ impl<'io> FileRef<'io> {
|
||||||
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
// to this, ensuring that it will not be mutated as per the aliasing rules.
|
||||||
file.as_mut()
|
file.as_mut()
|
||||||
});
|
});
|
||||||
let file_pin = file_ref.map(|file| unsafe { Pin::new_unchecked(file) });
|
let file_this = file_ref.map(|file| unsafe { RefThisMut::new(file) });
|
||||||
file_pin.map(|file| File::new(file))
|
file_this.map(|this| File::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,63 +1,51 @@
|
||||||
pub use super::bridge::CPPFLACFile;
|
pub use super::bridge::CPPFLACFile;
|
||||||
pub use super::bridge::CPPFLACPicture;
|
pub use super::bridge::CPPFLACPicture;
|
||||||
use super::bridge::{CPPPictureList, FLACFile_pictureList, PictureList_to_vector, Picture_data};
|
use super::bridge::{CPPPictureList, FLACFile_pictureList, PictureList_to_vector, Picture_data, CPPByteVector};
|
||||||
use super::tk::ByteVector;
|
use super::tk::{ByteVector, OwnedByteVector};
|
||||||
pub use super::xiph::XiphComment;
|
pub use super::xiph::XiphComment;
|
||||||
|
use super::this::{OwnedThis, RefThisMut, RefThis, This, ThisMut};
|
||||||
use cxx::UniquePtr;
|
use cxx::UniquePtr;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
pub struct FLACFile<'file_ref> {
|
pub struct FLACFile<'file_ref> {
|
||||||
this: Pin<&'file_ref mut CPPFLACFile>,
|
this: RefThisMut<'file_ref, CPPFLACFile>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> FLACFile<'file_ref> {
|
impl<'file_ref> FLACFile<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref mut CPPFLACFile>) -> Self {
|
pub(super) fn new(this: RefThisMut<'file_ref, CPPFLACFile>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn xiph_comments(&mut self) -> Option<XiphComment<'file_ref>> {
|
pub fn xiph_comments(&mut self) -> Option<XiphComment<'file_ref>> {
|
||||||
let this = self.this.as_mut();
|
let tag = self.this.pin_mut().xiphComment(false);
|
||||||
let tag = this.xiphComment(false);
|
|
||||||
let tag_ref = unsafe {
|
let tag_ref = unsafe {
|
||||||
// SAFETY: This pointer is a valid type, and can only used and accessed
|
// 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.
|
// via this function and thus cannot be mutated, satisfying the aliasing rules.
|
||||||
tag.as_mut()
|
tag.as_mut()
|
||||||
};
|
};
|
||||||
let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) });
|
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
|
||||||
tag_pin.map(|tag| XiphComment::new(tag))
|
tag_this.map(|this| XiphComment::new(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn picture_list(&mut self) -> PictureList<'file_ref> {
|
pub fn picture_list(&mut self) -> Option<PictureList<'file_ref>> {
|
||||||
let pictures = FLACFile_pictureList(self.this.as_mut());
|
let pictures = FLACFile_pictureList(self.this.pin_mut());
|
||||||
PictureList::new(pictures)
|
let this = unsafe { OwnedThis::new(pictures) };
|
||||||
|
this.map(|this| PictureList::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PictureList<'file_ref> {
|
pub struct PictureList<'file_ref> {
|
||||||
// PictureList is implicitly tied to the lifetime of the file_ref, despite us technically
|
this: OwnedThis<'file_ref, CPPPictureList>,
|
||||||
// """""owning"""" it.
|
|
||||||
_data: PhantomData<&'file_ref CPPFLACPicture>,
|
|
||||||
// Only in a UniquePtr because we can't marshal over ownership of the PictureList by itself over cxx.
|
|
||||||
this: UniquePtr<CPPPictureList>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> PictureList<'file_ref> {
|
impl<'file_ref> PictureList<'file_ref> {
|
||||||
pub(super) fn new(this: UniquePtr<CPPPictureList>) -> Self {
|
pub(super) fn new(this: OwnedThis<'file_ref, CPPPictureList>) -> Self {
|
||||||
Self {
|
Self { this }
|
||||||
_data: PhantomData,
|
|
||||||
this,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_vec(&self) -> Vec<Picture<'file_ref>> {
|
pub fn to_vec(&self) -> Vec<Picture<'file_ref>> {
|
||||||
let pictures = PictureList_to_vector(unsafe {
|
let pictures = PictureList_to_vector(self.this.pin());
|
||||||
// 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();
|
let mut result = Vec::new();
|
||||||
for picture_ptr in pictures.iter() {
|
for picture_ptr in pictures.iter() {
|
||||||
let picture_ptr = picture_ptr.get();
|
let picture_ptr = picture_ptr.get();
|
||||||
|
@ -66,24 +54,25 @@ impl<'file_ref> PictureList<'file_ref> {
|
||||||
// via this function and thus cannot be mutated, satisfying the aliasing rules.
|
// via this function and thus cannot be mutated, satisfying the aliasing rules.
|
||||||
picture_ptr.as_ref().unwrap()
|
picture_ptr.as_ref().unwrap()
|
||||||
};
|
};
|
||||||
let picture_pin = unsafe { Pin::new_unchecked(picture_ref) };
|
let picture_this = unsafe { RefThis::new(picture_ref) };
|
||||||
result.push(Picture::new(picture_pin));
|
result.push(Picture::new(picture_this));
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Picture<'file_ref> {
|
pub struct Picture<'file_ref> {
|
||||||
this: Pin<&'file_ref CPPFLACPicture>,
|
this: RefThis<'file_ref, CPPFLACPicture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> Picture<'file_ref> {
|
impl<'file_ref> Picture<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref CPPFLACPicture>) -> Self {
|
pub(super) fn new(this: RefThis<'file_ref, CPPFLACPicture>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data(&self) -> ByteVector<'file_ref> {
|
pub fn data(&self) -> Option<OwnedByteVector<'file_ref>> {
|
||||||
let data = Picture_data(self.this);
|
let data = Picture_data(self.this.pin());
|
||||||
ByteVector::new(data)
|
let this = unsafe { OwnedThis::new(data) };
|
||||||
|
this.map(|this| ByteVector::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,129 +1,126 @@
|
||||||
use super::bridge::{
|
use super::bridge::{
|
||||||
self, CPPID3v2AttachedPictureFrame, CPPID3v2Frame, CPPID3v2FrameList, CPPID3v2Tag,
|
self, CPPID3v2AttachedPictureFrame, CPPID3v2Frame, CPPID3v2FrameList, CPPID3v2Tag,
|
||||||
CPPID3v2TextIdentificationFrame, CPPID3v2UserTextIdentificationFrame,
|
CPPID3v2TextIdentificationFrame, CPPID3v2UserTextIdentificationFrame, CPPStringList, CPPByteVector,
|
||||||
};
|
};
|
||||||
use super::tk::{ByteVector, StringList};
|
use super::tk::{ByteVector, StringList, OwnedByteVector, OwnedStringList};
|
||||||
use cxx::UniquePtr;
|
use super::this::{OwnedThis, RefThisMut, RefThis, This};
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::pin::Pin;
|
|
||||||
|
|
||||||
pub struct ID3v2Tag<'file_ref> {
|
pub struct ID3v2Tag<'file_ref> {
|
||||||
this: Pin<&'file_ref CPPID3v2Tag>,
|
this: RefThisMut<'file_ref, CPPID3v2Tag>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> ID3v2Tag<'file_ref> {
|
impl<'file_ref> ID3v2Tag<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref CPPID3v2Tag>) -> Self {
|
pub(super) fn new(this: RefThisMut<'file_ref, CPPID3v2Tag>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frames(&self) -> FrameList<'file_ref> {
|
pub fn frames(&self) -> Option<FrameList<'file_ref>> {
|
||||||
let frames = bridge::Tag_frameList(self.this.as_ref());
|
let frames = bridge::Tag_frameList(self.this.pin());
|
||||||
FrameList::new(frames)
|
let this = unsafe { OwnedThis::new(frames) };
|
||||||
|
this.map(|this| FrameList::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FrameList<'file_ref> {
|
pub struct FrameList<'file_ref> {
|
||||||
_data: PhantomData<&'file_ref CPPID3v2FrameList>,
|
this: OwnedThis<'file_ref, CPPID3v2FrameList>,
|
||||||
this: UniquePtr<CPPID3v2FrameList>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> FrameList<'file_ref> {
|
impl<'file_ref> FrameList<'file_ref> {
|
||||||
pub(super) fn new(this: UniquePtr<CPPID3v2FrameList>) -> Self {
|
pub(super) fn new(this: OwnedThis<'file_ref, CPPID3v2FrameList>) -> Self {
|
||||||
Self {
|
Self { this }
|
||||||
_data: PhantomData,
|
|
||||||
this,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_vec(&self) -> Vec<Frame<'file_ref>> {
|
pub fn to_vec(&self) -> Vec<Frame<'file_ref>> {
|
||||||
let this = unsafe { Pin::new_unchecked(self.this.as_ref().unwrap()) };
|
let frames = bridge::FrameList_to_vector(self.this.pin());
|
||||||
let frames = bridge::FrameList_to_vector(this);
|
|
||||||
frames
|
frames
|
||||||
.iter()
|
.iter()
|
||||||
.map(|frame| {
|
.map(|frame| {
|
||||||
let frame_ptr = frame.get();
|
let frame_ptr = frame.get();
|
||||||
let frame_ref = unsafe { frame_ptr.as_ref().unwrap() };
|
let frame_ref = unsafe { frame_ptr.as_ref().unwrap() };
|
||||||
let frame_pin = unsafe { Pin::new_unchecked(frame_ref) };
|
let frame_this = unsafe { RefThis::new(frame_ref) };
|
||||||
Frame::new(frame_pin)
|
Frame::new(frame_this)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Frame<'file_ref> {
|
pub struct Frame<'file_ref> {
|
||||||
this: Pin<&'file_ref CPPID3v2Frame>,
|
this: RefThis<'file_ref, CPPID3v2Frame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> Frame<'file_ref> {
|
impl<'file_ref> Frame<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref CPPID3v2Frame>) -> Self {
|
pub(super) fn new(this: RefThis<'file_ref, CPPID3v2Frame>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_text_identification(&mut self) -> Option<TextIdentificationFrame<'file_ref>> {
|
pub fn as_text_identification(&mut self) -> Option<TextIdentificationFrame<'file_ref>> {
|
||||||
let frame = unsafe { bridge::Frame_asTextIdentification(self.this.as_ref().get_ref()) };
|
let frame = unsafe { bridge::Frame_asTextIdentification(self.this.ptr()) };
|
||||||
let frame_ref = unsafe { frame.as_ref() };
|
let frame_ref = unsafe { frame.as_ref() };
|
||||||
let frame_pin = frame_ref.map(|frame| unsafe { Pin::new_unchecked(frame) });
|
let frame_this = frame_ref.map(|frame| unsafe { RefThis::new(frame) });
|
||||||
frame_pin.map(|frame| TextIdentificationFrame::new(frame))
|
frame_this.map(|this| TextIdentificationFrame::new(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_user_text_identification(
|
pub fn as_user_text_identification(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Option<UserTextIdentificationFrame<'file_ref>> {
|
) -> Option<UserTextIdentificationFrame<'file_ref>> {
|
||||||
let frame = unsafe { bridge::Frame_asUserTextIdentification(self.this.as_ref().get_ref()) };
|
let frame = unsafe { bridge::Frame_asUserTextIdentification(self.this.ptr()) };
|
||||||
let frame_ref = unsafe { frame.as_ref() };
|
let frame_ref = unsafe { frame.as_ref() };
|
||||||
let frame_pin = frame_ref.map(|frame| unsafe { Pin::new_unchecked(frame) });
|
let frame_this = frame_ref.map(|frame| unsafe { RefThis::new(frame) });
|
||||||
frame_pin.map(|frame| UserTextIdentificationFrame::new(frame))
|
frame_this.map(|this| UserTextIdentificationFrame::new(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_attached_picture(&mut self) -> Option<AttachedPictureFrame<'file_ref>> {
|
pub fn as_attached_picture(&mut self) -> Option<AttachedPictureFrame<'file_ref>> {
|
||||||
let frame = unsafe { bridge::Frame_asAttachedPicture(self.this.as_ref().get_ref()) };
|
let frame = unsafe { bridge::Frame_asAttachedPicture(self.this.ptr()) };
|
||||||
let frame_ref = unsafe { frame.as_ref() };
|
let frame_ref = unsafe { frame.as_ref() };
|
||||||
let frame_pin = frame_ref.map(|frame| unsafe { Pin::new_unchecked(frame) });
|
let frame_this = frame_ref.map(|frame| unsafe { RefThis::new(frame) });
|
||||||
frame_pin.map(|frame| AttachedPictureFrame::new(frame))
|
frame_this.map(|this| AttachedPictureFrame::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextIdentificationFrame<'file_ref> {
|
pub struct TextIdentificationFrame<'file_ref> {
|
||||||
this: Pin<&'file_ref CPPID3v2TextIdentificationFrame>,
|
this: RefThis<'file_ref, CPPID3v2TextIdentificationFrame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> TextIdentificationFrame<'file_ref> {
|
impl<'file_ref> TextIdentificationFrame<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref CPPID3v2TextIdentificationFrame>) -> Self {
|
pub(super) fn new(this: RefThis<'file_ref, CPPID3v2TextIdentificationFrame>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn field_list(&self) -> StringList<'file_ref> {
|
pub fn field_list(&self) -> Option<OwnedStringList<'file_ref>> {
|
||||||
let field_list = bridge::TextIdentificationFrame_fieldList(self.this);
|
let field_list = bridge::TextIdentificationFrame_fieldList(self.this.pin());
|
||||||
StringList::owned(field_list)
|
let this = unsafe { OwnedThis::new(field_list) };
|
||||||
|
this.map(|this| StringList::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserTextIdentificationFrame<'file_ref> {
|
pub struct UserTextIdentificationFrame<'file_ref> {
|
||||||
this: Pin<&'file_ref CPPID3v2UserTextIdentificationFrame>,
|
this: RefThis<'file_ref, CPPID3v2UserTextIdentificationFrame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> UserTextIdentificationFrame<'file_ref> {
|
impl<'file_ref> UserTextIdentificationFrame<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref CPPID3v2UserTextIdentificationFrame>) -> Self {
|
pub(super) fn new(this: RefThis<'file_ref, CPPID3v2UserTextIdentificationFrame>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn values(&self) -> StringList<'file_ref> {
|
pub fn values(&self) -> Option<OwnedStringList<'file_ref>> {
|
||||||
let values = bridge::UserTextIdentificationFrame_fieldList(self.this);
|
let values = bridge::UserTextIdentificationFrame_fieldList(self.this.pin());
|
||||||
StringList::owned(values)
|
let this = unsafe { OwnedThis::new(values) };
|
||||||
|
this.map(|this| StringList::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AttachedPictureFrame<'file_ref> {
|
pub struct AttachedPictureFrame<'file_ref> {
|
||||||
this: Pin<&'file_ref CPPID3v2AttachedPictureFrame>,
|
this: RefThis<'file_ref, CPPID3v2AttachedPictureFrame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> AttachedPictureFrame<'file_ref> {
|
impl<'file_ref> AttachedPictureFrame<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref CPPID3v2AttachedPictureFrame>) -> Self {
|
pub(super) fn new(this: RefThis<'file_ref, CPPID3v2AttachedPictureFrame>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn picture(&self) -> ByteVector<'file_ref> {
|
pub fn picture(&self) -> Option<OwnedByteVector<'file_ref>> {
|
||||||
let picture = bridge::AttachedPictureFrame_picture(self.this.as_ref());
|
let picture = bridge::AttachedPictureFrame_picture(self.this.pin());
|
||||||
ByteVector::new(picture)
|
let this = unsafe { OwnedThis::new(picture) };
|
||||||
|
this.map(|this| ByteVector::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,3 +10,4 @@ pub mod mpeg;
|
||||||
pub mod ogg;
|
pub mod ogg;
|
||||||
pub mod tk;
|
pub mod tk;
|
||||||
pub mod xiph;
|
pub mod xiph;
|
||||||
|
pub mod this;
|
|
@ -1,20 +1,21 @@
|
||||||
use super::bridge::{self, CPPMPEGFile};
|
use super::bridge::{self, CPPMPEGFile};
|
||||||
use super::id3v2::ID3v2Tag;
|
use super::id3v2::ID3v2Tag;
|
||||||
|
use super::this::{RefThisMut, This, ThisMut};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
pub struct MPEGFile<'file_ref> {
|
pub struct MPEGFile<'file_ref> {
|
||||||
this: Pin<&'file_ref mut CPPMPEGFile>,
|
this: RefThisMut<'file_ref, CPPMPEGFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> MPEGFile<'file_ref> {
|
impl<'file_ref> MPEGFile<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref mut CPPMPEGFile>) -> Self {
|
pub(super) fn new(this: RefThisMut<'file_ref, CPPMPEGFile>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id3v2_tag(&mut self) -> Option<ID3v2Tag<'file_ref>> {
|
pub fn id3v2_tag(&mut self) -> Option<ID3v2Tag<'file_ref>> {
|
||||||
let tag = self.this.as_mut().ID3v2Tag(false);
|
let tag = self.this.pin_mut().ID3v2Tag(false);
|
||||||
let tag_ref = unsafe { tag.as_ref() };
|
let tag_ref = unsafe { tag.as_mut() };
|
||||||
let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) });
|
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
|
||||||
tag_pin.map(|tag| ID3v2Tag::new(tag))
|
tag_this.map(|this| ID3v2Tag::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +1,46 @@
|
||||||
pub use super::bridge::{CPPOpusFile, CPPVorbisFile};
|
pub use super::bridge::{CPPOpusFile, CPPVorbisFile};
|
||||||
use super::xiph::XiphComment;
|
use super::xiph::XiphComment;
|
||||||
|
use super::this::{RefThisMut, RefThis, This};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
pub struct VorbisFile<'file_ref> {
|
pub struct VorbisFile<'file_ref> {
|
||||||
this: Pin<&'file_ref mut CPPVorbisFile>,
|
this: RefThisMut<'file_ref, CPPVorbisFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> VorbisFile<'file_ref> {
|
impl<'file_ref> VorbisFile<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref mut CPPVorbisFile>) -> Self {
|
pub(super) fn new(this: RefThisMut<'file_ref, CPPVorbisFile>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn xiph_comments(&self) -> Option<XiphComment<'file_ref>> {
|
pub fn xiph_comments(&self) -> Option<XiphComment<'file_ref>> {
|
||||||
let this = self.this.as_ref();
|
let tag = self.this.pin().vorbisTag();
|
||||||
let tag = this.vorbisTag();
|
|
||||||
let tag_ref = unsafe {
|
let tag_ref = unsafe {
|
||||||
// SAFETY: This pointer is a valid type, and can only used and accessed
|
// 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.
|
// via this function and thus cannot be mutated, satisfying the aliasing rules.
|
||||||
tag.as_mut()
|
tag.as_mut()
|
||||||
};
|
};
|
||||||
let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) });
|
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
|
||||||
tag_pin.map(|tag| XiphComment::new(tag))
|
tag_this.map(|this| XiphComment::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OpusFile<'file_ref> {
|
pub struct OpusFile<'file_ref> {
|
||||||
this: Pin<&'file_ref mut CPPOpusFile>,
|
this: RefThisMut<'file_ref, CPPOpusFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> OpusFile<'file_ref> {
|
impl<'file_ref> OpusFile<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref mut CPPOpusFile>) -> Self {
|
pub(super) fn new(this: RefThisMut<'file_ref, CPPOpusFile>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn xiph_comments(&self) -> Option<XiphComment<'file_ref>> {
|
pub fn xiph_comments(&self) -> Option<XiphComment<'file_ref>> {
|
||||||
let this = self.this.as_ref();
|
let tag = self.this.pin().opusTag();
|
||||||
let tag = this.opusTag();
|
|
||||||
let tag_ref = unsafe {
|
let tag_ref = unsafe {
|
||||||
// SAFETY: This pointer is a valid type, and can only used and accessed
|
// 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.
|
// via this function and thus cannot be mutated, satisfying the aliasing rules.
|
||||||
tag.as_mut()
|
tag.as_mut()
|
||||||
};
|
};
|
||||||
let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) });
|
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
|
||||||
tag_pin.map(|tag| XiphComment::new(tag))
|
tag_this.map(|this| XiphComment::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
94
musikr/src/main/jni/src/taglib/this.rs
Normal file
94
musikr/src/main/jni/src/taglib/this.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use cxx::{UniquePtr, memory::UniquePtrTarget};
|
||||||
|
|
||||||
|
pub trait This<'file_ref, T> {
|
||||||
|
fn pin(&self) -> Pin<&T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ThisMut<'file_ref, T> : This<'file_ref, T> {
|
||||||
|
fn pin_mut(&mut self) -> Pin<&mut T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RefThis<'file_ref, T> {
|
||||||
|
this: &'file_ref T
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref, T> RefThis<'file_ref, T> {
|
||||||
|
pub unsafe fn new(this: &'file_ref T) -> Self {
|
||||||
|
// Rough informal contact is that the reference points to a C++ object
|
||||||
|
// that will live and not move for as long as 'file_ref.
|
||||||
|
Self { this }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptr(&self) -> *const T {
|
||||||
|
self.this as *const T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref, T> This<'file_ref, T> for RefThis<'file_ref, T> {
|
||||||
|
fn pin(&self) -> Pin<&T> {
|
||||||
|
unsafe { Pin::new_unchecked(self.this) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RefThisMut<'file_ref, T> {
|
||||||
|
this: &'file_ref mut T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref, T> RefThisMut<'file_ref, T> {
|
||||||
|
pub unsafe fn new(this: &'file_ref mut T) -> Self {
|
||||||
|
Self { this }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptr(&self) -> *const T {
|
||||||
|
self.this as *const T
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptr_mut(&mut self) -> *mut T {
|
||||||
|
self.this as *mut T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref, T> This<'file_ref, T> for RefThisMut<'file_ref, T> {
|
||||||
|
fn pin(&self) -> Pin<&T> {
|
||||||
|
unsafe { Pin::new_unchecked(self.this) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref, T> ThisMut<'file_ref, T> for RefThisMut<'file_ref, T> {
|
||||||
|
fn pin_mut(&mut self) -> Pin<&mut T> {
|
||||||
|
unsafe { Pin::new_unchecked(self.this) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OwnedThis<'file_ref, T : UniquePtrTarget> {
|
||||||
|
_data: PhantomData<&'file_ref ()>,
|
||||||
|
this: UniquePtr<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref, T : UniquePtrTarget> OwnedThis<'file_ref, T> {
|
||||||
|
pub unsafe fn new(this: UniquePtr<T>) -> Option<Self> {
|
||||||
|
if !this.is_null() {
|
||||||
|
Some(Self {
|
||||||
|
_data: PhantomData,
|
||||||
|
this,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref, T : UniquePtrTarget> This<'file_ref, T> for OwnedThis<'file_ref, T> {
|
||||||
|
fn pin(&self) -> Pin<&T> {
|
||||||
|
unsafe { Pin::new_unchecked(self.this.as_ref().unwrap()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref, T : UniquePtrTarget> ThisMut<'file_ref, T> for OwnedThis<'file_ref, T> {
|
||||||
|
fn pin_mut(&mut self) -> Pin<&mut T> {
|
||||||
|
self.this.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,32 +1,24 @@
|
||||||
use super::bridge::{self, CPPByteVector, CPPString, CPPStringList};
|
use super::bridge::{self, CPPByteVector, CPPString, CPPStringList};
|
||||||
|
use super::this::{RefThis, RefThisMut, This, OwnedThis};
|
||||||
use cxx::{memory::UniquePtrTarget, UniquePtr};
|
use cxx::{memory::UniquePtrTarget, UniquePtr};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::{ffi::CStr, string::ToString};
|
use std::{ffi::CStr, string::ToString};
|
||||||
|
|
||||||
enum This<'file_ref, T: UniquePtrTarget> {
|
pub(super) struct String<'file_ref, T: This<'file_ref, CPPString>> {
|
||||||
Owned {
|
_data: PhantomData<&'file_ref ()>,
|
||||||
data: PhantomData<&'file_ref T>,
|
this: T,
|
||||||
this: UniquePtr<T>,
|
|
||||||
},
|
|
||||||
Ref {
|
|
||||||
this: Pin<&'file_ref T>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct String<'file_ref> {
|
impl<'file_ref, T: This<'file_ref, CPPString>> String<'file_ref, T> {
|
||||||
this: Pin<&'file_ref CPPString>,
|
pub(super) fn new(this: T) -> Self {
|
||||||
}
|
Self { _data: PhantomData, this }
|
||||||
|
|
||||||
impl<'file_ref> String<'file_ref> {
|
|
||||||
pub(super) fn new(this: Pin<&'file_ref CPPString>) -> Self {
|
|
||||||
Self { this }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> ToString for String<'file_ref> {
|
impl<'file_ref, T: This<'file_ref, CPPString>> ToString for String<'file_ref, T> {
|
||||||
fn to_string(&self) -> std::string::String {
|
fn to_string(&self) -> std::string::String {
|
||||||
let c_str = self.this.toCString(true);
|
let c_str = self.this.pin().toCString(true);
|
||||||
unsafe {
|
unsafe {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - This is a C-string returned by a C++ method guaranteed to have
|
// - This is a C-string returned by a C++ method guaranteed to have
|
||||||
|
@ -44,67 +36,47 @@ impl<'file_ref> ToString for String<'file_ref> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StringList<'file_ref> {
|
pub type OwnedString<'file_ref> = String<'file_ref, OwnedThis<'file_ref, CPPString>>;
|
||||||
this: This<'file_ref, CPPStringList>,
|
pub type RefString<'file_ref> = String<'file_ref, RefThis<'file_ref, CPPString>>;
|
||||||
|
pub type RefStringMut<'file_ref> = String<'file_ref, RefThisMut<'file_ref, CPPString>>;
|
||||||
|
pub(super) struct StringList<'file_ref, T: This<'file_ref, CPPStringList>> {
|
||||||
|
_data: PhantomData<&'file_ref ()>,
|
||||||
|
this: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> StringList<'file_ref> {
|
pub type OwnedStringList<'file_ref> = StringList<'file_ref, OwnedThis<'file_ref, CPPStringList>>;
|
||||||
pub(super) fn owned(this: UniquePtr<CPPStringList>) -> Self {
|
pub type RefStringList<'file_ref> = StringList<'file_ref, RefThis<'file_ref, CPPStringList>>;
|
||||||
Self {
|
pub type RefStringListMut<'file_ref> = StringList<'file_ref, RefThisMut<'file_ref, CPPStringList>>;
|
||||||
this: This::Owned {
|
|
||||||
data: PhantomData,
|
|
||||||
this,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn reference(this: Pin<&'file_ref CPPStringList>) -> Self {
|
impl<'file_ref, T: This<'file_ref, CPPStringList>> StringList<'file_ref, T> {
|
||||||
Self {
|
pub(super) fn new(this: T) -> Self {
|
||||||
this: This::Ref { this },
|
Self { _data: PhantomData, this }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_vec(&self) -> Vec<std::string::String> {
|
pub fn to_vec(&self) -> Vec<std::string::String> {
|
||||||
let pin = match &self.this {
|
let cxx_values = bridge::StringList_to_vector(self.this.pin());
|
||||||
This::Owned { this, .. } => unsafe { Pin::new_unchecked(this.as_ref().unwrap()) },
|
|
||||||
This::Ref { this } => *this,
|
|
||||||
};
|
|
||||||
let cxx_values = bridge::StringList_to_vector(pin);
|
|
||||||
cxx_values
|
cxx_values
|
||||||
.iter()
|
.iter()
|
||||||
.map(|value| {
|
.map(|value| {
|
||||||
let this = unsafe { Pin::new_unchecked(value) };
|
let this = unsafe { RefThis::new(value) };
|
||||||
String::new(this).to_string()
|
String::new(this).to_string()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ByteVector<'file_ref> {
|
pub struct ByteVector<'file_ref, T: This<'file_ref, CPPByteVector>> {
|
||||||
// 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<&'file_ref CPPByteVector>,
|
_data: PhantomData<&'file_ref CPPByteVector>,
|
||||||
this: UniquePtr<CPPByteVector>,
|
this: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> ByteVector<'file_ref> {
|
impl<'file_ref, T: This<'file_ref, CPPByteVector>> ByteVector<'file_ref, T> {
|
||||||
pub(super) fn new(this: UniquePtr<CPPByteVector>) -> Self {
|
pub(super) fn new(this: T) -> Self {
|
||||||
Self {
|
Self { _data: PhantomData, this }
|
||||||
_data: PhantomData,
|
|
||||||
this,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_vec(&self) -> Vec<u8> {
|
pub fn to_vec(&self) -> Vec<u8> {
|
||||||
let this_ref = self.this.as_ref().unwrap();
|
let this = self.this.pin();
|
||||||
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.
|
|
||||||
Pin::new_unchecked(this_ref)
|
|
||||||
};
|
|
||||||
let size = this.size().try_into().unwrap();
|
let size = this.size().try_into().unwrap();
|
||||||
let data = this.data();
|
let data = this.data();
|
||||||
// Re-cast to u8
|
// Re-cast to u8
|
||||||
|
@ -118,3 +90,7 @@ impl<'file_ref> ByteVector<'file_ref> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type OwnedByteVector<'file_ref> = ByteVector<'file_ref, OwnedThis<'file_ref, CPPByteVector>>;
|
||||||
|
pub type RefByteVector<'file_ref> = ByteVector<'file_ref, RefThis<'file_ref, CPPByteVector>>;
|
||||||
|
pub type RefByteVectorMut<'file_ref> = ByteVector<'file_ref, RefThisMut<'file_ref, CPPByteVector>>;
|
||||||
|
|
|
@ -2,36 +2,32 @@ pub use super::bridge::CPPXiphComment;
|
||||||
use super::bridge::{CPPFieldListMap, FieldListMap_to_entries, XiphComment_pictureList};
|
use super::bridge::{CPPFieldListMap, FieldListMap_to_entries, XiphComment_pictureList};
|
||||||
pub use super::flac::PictureList;
|
pub use super::flac::PictureList;
|
||||||
use super::tk;
|
use super::tk;
|
||||||
|
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut, This};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
pub struct XiphComment<'file_ref> {
|
pub struct XiphComment<'file_ref> {
|
||||||
this: Pin<&'file_ref mut CPPXiphComment>,
|
this: RefThisMut<'file_ref, CPPXiphComment>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> XiphComment<'file_ref> {
|
impl<'file_ref> XiphComment<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref mut CPPXiphComment>) -> Self {
|
pub fn new(this: RefThisMut<'file_ref, CPPXiphComment>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn field_list_map<'slf>(&'slf self) -> FieldListMap<'file_ref> {
|
pub fn field_list_map<'slf>(&'slf self) -> FieldListMap<'file_ref> {
|
||||||
// To call the method we need, we have to get our mut reference down to an immutable
|
let map: &'slf CPPFieldListMap = self.this.pin().fieldListMap();
|
||||||
// reference. The safe API can do this, but shortens the lifecycle to at most self, even
|
// CPPFieldListMap exists for as long as the XiphComment, so we can transmute it
|
||||||
// though the reference really lives as long as file_ref. Sadly, this requires us to transmute
|
// to the file_ref lifetime.
|
||||||
// to extend the lifecycle back. This new pointer is really unsafe (we now have both a mut
|
let extended_map: &'file_ref CPPFieldListMap = unsafe { std::mem::transmute(map) };
|
||||||
// and an immutable reference to the same object), but it's dropped after this call.
|
let map_pin = unsafe { Pin::new_unchecked(extended_map) };
|
||||||
// The value returned is unable to actually mutate this object, so it's safe.
|
|
||||||
let this_ref: &'slf CPPXiphComment = self.this.as_ref().get_ref();
|
|
||||||
let extended_ref: &'file_ref CPPXiphComment = unsafe { std::mem::transmute(this_ref) };
|
|
||||||
let this: Pin<&'file_ref CPPXiphComment> = unsafe { Pin::new_unchecked(extended_ref) };
|
|
||||||
let map = this.fieldListMap();
|
|
||||||
let map_pin = unsafe { Pin::new_unchecked(map) };
|
|
||||||
FieldListMap::new(map_pin)
|
FieldListMap::new(map_pin)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn picture_list(&mut self) -> PictureList<'file_ref> {
|
pub fn picture_list(&mut self) -> Option<PictureList<'file_ref>> {
|
||||||
let pictures = XiphComment_pictureList(self.this.as_mut());
|
let pictures = XiphComment_pictureList(self.this.pin_mut());
|
||||||
PictureList::new(pictures)
|
let pictures_this = unsafe { OwnedThis::new(pictures) };
|
||||||
|
pictures_this.map(|this| PictureList::new(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +36,7 @@ pub struct FieldListMap<'file_ref> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'file_ref> FieldListMap<'file_ref> {
|
impl<'file_ref> FieldListMap<'file_ref> {
|
||||||
pub(super) fn new(this: Pin<&'file_ref CPPFieldListMap>) -> Self {
|
pub fn new(this: Pin<&'file_ref CPPFieldListMap>) -> Self {
|
||||||
Self { this }
|
Self { this }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,11 +55,11 @@ impl<'file_ref> FieldListMap<'file_ref> {
|
||||||
// of self.
|
// of self.
|
||||||
let property_pin = unsafe { Pin::new_unchecked(property) };
|
let property_pin = unsafe { Pin::new_unchecked(property) };
|
||||||
let key_ref = property_pin.key();
|
let key_ref = property_pin.key();
|
||||||
let key_pin = unsafe { Pin::new_unchecked(key_ref) };
|
let key_this = unsafe { RefThis::new(key_ref) };
|
||||||
let key = tk::String::new(key_pin).to_string();
|
let key = tk::String::new(key_this).to_string();
|
||||||
let value_ref = property_pin.value();
|
let value_ref = property_pin.value();
|
||||||
let value_pin = unsafe { Pin::new_unchecked(value_ref) };
|
let value_this = unsafe { RefThis::new(value_ref) };
|
||||||
let value = tk::StringList::reference(value_pin).to_vec();
|
let value = tk::StringList::new(value_this).to_vec();
|
||||||
(key, value)
|
(key, value)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
Loading…
Reference in a new issue