diff --git a/musikr/src/main/jni/src/taglib/audioproperties.rs b/musikr/src/main/jni/src/taglib/audioproperties.rs index b151a151b..af1cbc0e3 100644 --- a/musikr/src/main/jni/src/taglib/audioproperties.rs +++ b/musikr/src/main/jni/src/taglib/audioproperties.rs @@ -1,28 +1,29 @@ use super::bridge::CppAudioProperties; +use super::this::{RefThis, This}; use std::pin::Pin; pub struct AudioProperties<'file_ref> { - this: Pin<&'file_ref CppAudioProperties>, + this: RefThis<'file_ref, CppAudioProperties>, } 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 } } pub fn length_in_milliseconds(&self) -> i32 { - self.this.as_ref().lengthInMilliseconds() + self.this.pin().lengthInMilliseconds() } pub fn bitrate(&self) -> i32 { - self.this.as_ref().bitrate() + self.this.pin().bitrate() } pub fn sample_rate(&self) -> i32 { - self.this.as_ref().sampleRate() + self.this.pin().sampleRate() } pub fn channels(&self) -> i32 { - self.this.as_ref().channels() + self.this.pin().channels() } } diff --git a/musikr/src/main/jni/src/taglib/file.rs b/musikr/src/main/jni/src/taglib/file.rs index 470f2e243..a25f024c3 100644 --- a/musikr/src/main/jni/src/taglib/file.rs +++ b/musikr/src/main/jni/src/taglib/file.rs @@ -5,19 +5,20 @@ use super::id3v2::ID3v2Tag; use super::mpeg::MPEGFile; use super::ogg::OpusFile; use super::ogg::VorbisFile; +use super::this::{RefThisMut, RefThis, This, ThisMut}; use std::pin::Pin; pub struct File<'file_ref> { - this: Pin<&'file_ref mut CPPFile>, + this: RefThisMut<'file_ref, CPPFile> } 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 } } pub fn audio_properties(&self) -> Option> { - let props_ptr = self.this.as_ref().audioProperties(); + let props_ptr = self.this.pin().audioProperties(); let props_ref = unsafe { // SAFETY: // - 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. props_ptr.as_ref() }; - let props_pin = props_ref.map(|props| unsafe { Pin::new_unchecked(props) }); - props_pin.map(|props| AudioProperties::new(props)) + let props_this = props_ref.map(|props| unsafe { RefThis::new(props) }); + props_this.map(|this| AudioProperties::new(this)) } pub fn as_opus(&mut self) -> Option> { @@ -37,7 +38,7 @@ impl<'file_ref> File<'file_ref> { // 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 // 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 { // 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. opus_file.as_mut() }; - let opus_pin = opus_ref.map(|opus| unsafe { Pin::new_unchecked(opus) }); - opus_pin.map(|opus| OpusFile::new(opus)) + let opus_this = opus_ref.map(|opus| unsafe { RefThisMut::new(opus) }); + opus_this.map(|this| OpusFile::new(this)) } pub fn as_vorbis(&mut self) -> Option> { @@ -58,7 +59,7 @@ impl<'file_ref> File<'file_ref> { // 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 // 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 { // 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. vorbis_file.as_mut() }; - let vorbis_pin = vorbis_ref.map(|vorbis| unsafe { Pin::new_unchecked(vorbis) }); - vorbis_pin.map(|vorbis| VorbisFile::new(vorbis)) + let vorbis_this = vorbis_ref.map(|vorbis| unsafe { RefThisMut::new(vorbis) }); + vorbis_this.map(|this| VorbisFile::new(this)) } pub fn as_flac(&mut self) -> Option> { @@ -79,7 +80,7 @@ impl<'file_ref> File<'file_ref> { // 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 // 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 { // 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. flac_file.as_mut() }; - let flac_pin = flac_ref.map(|flac| unsafe { Pin::new_unchecked(flac) }); - flac_pin.map(|flac| FLACFile::new(flac)) + let flac_this = flac_ref.map(|flac| unsafe { RefThisMut::new(flac) }); + flac_this.map(|this| FLACFile::new(this)) } pub fn as_mpeg(&mut self) -> Option> { @@ -100,7 +101,7 @@ impl<'file_ref> File<'file_ref> { // 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 // 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 { // 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. mpeg_file.as_mut() }; - let mpeg_pin = mpeg_ref.map(|mpeg| unsafe { Pin::new_unchecked(mpeg) }); - mpeg_pin.map(|mpeg| MPEGFile::new(mpeg)) + let mpeg_this = mpeg_ref.map(|mpeg| unsafe { RefThisMut::new(mpeg) }); + mpeg_this.map(|this| MPEGFile::new(this)) } } diff --git a/musikr/src/main/jni/src/taglib/file_ref.rs b/musikr/src/main/jni/src/taglib/file_ref.rs index d10ea8fea..9c93b6083 100644 --- a/musikr/src/main/jni/src/taglib/file_ref.rs +++ b/musikr/src/main/jni/src/taglib/file_ref.rs @@ -1,6 +1,7 @@ use super::bridge::{self, CPPFileRef}; use super::file::File; use super::iostream::{BridgedIOStream, IOStream}; +use super::this::RefThisMut; use cxx::UniquePtr; 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. file.as_mut() }); - let file_pin = file_ref.map(|file| unsafe { Pin::new_unchecked(file) }); - file_pin.map(|file| File::new(file)) + let file_this = file_ref.map(|file| unsafe { RefThisMut::new(file) }); + file_this.map(|this| File::new(this)) } } diff --git a/musikr/src/main/jni/src/taglib/flac.rs b/musikr/src/main/jni/src/taglib/flac.rs index 3f1056f97..685e0a7b0 100644 --- a/musikr/src/main/jni/src/taglib/flac.rs +++ b/musikr/src/main/jni/src/taglib/flac.rs @@ -1,63 +1,51 @@ pub use super::bridge::CPPFLACFile; pub use super::bridge::CPPFLACPicture; -use super::bridge::{CPPPictureList, FLACFile_pictureList, PictureList_to_vector, Picture_data}; -use super::tk::ByteVector; +use super::bridge::{CPPPictureList, FLACFile_pictureList, PictureList_to_vector, Picture_data, CPPByteVector}; +use super::tk::{ByteVector, OwnedByteVector}; pub use super::xiph::XiphComment; +use super::this::{OwnedThis, RefThisMut, RefThis, This, ThisMut}; use cxx::UniquePtr; use std::marker::PhantomData; use std::pin::Pin; pub struct FLACFile<'file_ref> { - this: Pin<&'file_ref mut CPPFLACFile>, + this: RefThisMut<'file_ref, CPPFLACFile> } 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 } } pub fn xiph_comments(&mut self) -> Option> { - let this = self.this.as_mut(); - let tag = this.xiphComment(false); + let tag = self.this.pin_mut().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. tag.as_mut() }; - let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) }); - tag_pin.map(|tag| XiphComment::new(tag)) + let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) }); + tag_this.map(|this| XiphComment::new(this)) } - pub fn picture_list(&mut self) -> PictureList<'file_ref> { - let pictures = FLACFile_pictureList(self.this.as_mut()); - PictureList::new(pictures) + pub fn picture_list(&mut self) -> Option> { + let pictures = FLACFile_pictureList(self.this.pin_mut()); + let this = unsafe { OwnedThis::new(pictures) }; + this.map(|this| PictureList::new(this)) } } pub struct PictureList<'file_ref> { - // PictureList is implicitly tied to the lifetime of the file_ref, despite us technically - // """""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, + this: OwnedThis<'file_ref, CPPPictureList>, } impl<'file_ref> PictureList<'file_ref> { - pub(super) fn new(this: UniquePtr) -> Self { - Self { - _data: PhantomData, - this, - } + pub(super) fn new(this: OwnedThis<'file_ref, CPPPictureList>) -> Self { + Self { this } } pub fn to_vec(&self) -> Vec> { - 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 pictures = PictureList_to_vector(self.this.pin()); let mut result = Vec::new(); for picture_ptr in pictures.iter() { 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. picture_ptr.as_ref().unwrap() }; - let picture_pin = unsafe { Pin::new_unchecked(picture_ref) }; - result.push(Picture::new(picture_pin)); + let picture_this = unsafe { RefThis::new(picture_ref) }; + result.push(Picture::new(picture_this)); } result } } pub struct Picture<'file_ref> { - this: Pin<&'file_ref CPPFLACPicture>, + this: RefThis<'file_ref, CPPFLACPicture>, } 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 } } - pub fn data(&self) -> ByteVector<'file_ref> { - let data = Picture_data(self.this); - ByteVector::new(data) + pub fn data(&self) -> Option> { + let data = Picture_data(self.this.pin()); + let this = unsafe { OwnedThis::new(data) }; + this.map(|this| ByteVector::new(this)) } } diff --git a/musikr/src/main/jni/src/taglib/id3v2.rs b/musikr/src/main/jni/src/taglib/id3v2.rs index c4448ed45..2c6cafb17 100644 --- a/musikr/src/main/jni/src/taglib/id3v2.rs +++ b/musikr/src/main/jni/src/taglib/id3v2.rs @@ -1,129 +1,126 @@ use super::bridge::{ self, CPPID3v2AttachedPictureFrame, CPPID3v2Frame, CPPID3v2FrameList, CPPID3v2Tag, - CPPID3v2TextIdentificationFrame, CPPID3v2UserTextIdentificationFrame, + CPPID3v2TextIdentificationFrame, CPPID3v2UserTextIdentificationFrame, CPPStringList, CPPByteVector, }; -use super::tk::{ByteVector, StringList}; -use cxx::UniquePtr; -use std::marker::PhantomData; -use std::pin::Pin; +use super::tk::{ByteVector, StringList, OwnedByteVector, OwnedStringList}; +use super::this::{OwnedThis, RefThisMut, RefThis, This}; pub struct ID3v2Tag<'file_ref> { - this: Pin<&'file_ref CPPID3v2Tag>, -} + this: RefThisMut<'file_ref, CPPID3v2Tag>, +} 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 } } - pub fn frames(&self) -> FrameList<'file_ref> { - let frames = bridge::Tag_frameList(self.this.as_ref()); - FrameList::new(frames) + pub fn frames(&self) -> Option> { + let frames = bridge::Tag_frameList(self.this.pin()); + let this = unsafe { OwnedThis::new(frames) }; + this.map(|this| FrameList::new(this)) } } pub struct FrameList<'file_ref> { - _data: PhantomData<&'file_ref CPPID3v2FrameList>, - this: UniquePtr, + this: OwnedThis<'file_ref, CPPID3v2FrameList>, } impl<'file_ref> FrameList<'file_ref> { - pub(super) fn new(this: UniquePtr) -> Self { - Self { - _data: PhantomData, - this, - } + pub(super) fn new(this: OwnedThis<'file_ref, CPPID3v2FrameList>) -> Self { + Self { this } } pub fn to_vec(&self) -> Vec> { - let this = unsafe { Pin::new_unchecked(self.this.as_ref().unwrap()) }; - let frames = bridge::FrameList_to_vector(this); + let frames = bridge::FrameList_to_vector(self.this.pin()); frames .iter() .map(|frame| { let frame_ptr = frame.get(); let frame_ref = unsafe { frame_ptr.as_ref().unwrap() }; - let frame_pin = unsafe { Pin::new_unchecked(frame_ref) }; - Frame::new(frame_pin) + let frame_this = unsafe { RefThis::new(frame_ref) }; + Frame::new(frame_this) }) .collect() } } pub struct Frame<'file_ref> { - this: Pin<&'file_ref CPPID3v2Frame>, + this: RefThis<'file_ref, CPPID3v2Frame>, } 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 } } pub fn as_text_identification(&mut self) -> Option> { - 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_pin = frame_ref.map(|frame| unsafe { Pin::new_unchecked(frame) }); - frame_pin.map(|frame| TextIdentificationFrame::new(frame)) + let frame_this = frame_ref.map(|frame| unsafe { RefThis::new(frame) }); + frame_this.map(|this| TextIdentificationFrame::new(this)) } pub fn as_user_text_identification( &mut self, ) -> Option> { - 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_pin = frame_ref.map(|frame| unsafe { Pin::new_unchecked(frame) }); - frame_pin.map(|frame| UserTextIdentificationFrame::new(frame)) + let frame_this = frame_ref.map(|frame| unsafe { RefThis::new(frame) }); + frame_this.map(|this| UserTextIdentificationFrame::new(this)) } pub fn as_attached_picture(&mut self) -> Option> { - 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_pin = frame_ref.map(|frame| unsafe { Pin::new_unchecked(frame) }); - frame_pin.map(|frame| AttachedPictureFrame::new(frame)) + let frame_this = frame_ref.map(|frame| unsafe { RefThis::new(frame) }); + frame_this.map(|this| AttachedPictureFrame::new(this)) } } pub struct TextIdentificationFrame<'file_ref> { - this: Pin<&'file_ref CPPID3v2TextIdentificationFrame>, + this: RefThis<'file_ref, CPPID3v2TextIdentificationFrame>, } 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 } } - pub fn field_list(&self) -> StringList<'file_ref> { - let field_list = bridge::TextIdentificationFrame_fieldList(self.this); - StringList::owned(field_list) + pub fn field_list(&self) -> Option> { + let field_list = bridge::TextIdentificationFrame_fieldList(self.this.pin()); + let this = unsafe { OwnedThis::new(field_list) }; + this.map(|this| StringList::new(this)) } } pub struct UserTextIdentificationFrame<'file_ref> { - this: Pin<&'file_ref CPPID3v2UserTextIdentificationFrame>, + this: RefThis<'file_ref, CPPID3v2UserTextIdentificationFrame>, } 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 } } - pub fn values(&self) -> StringList<'file_ref> { - let values = bridge::UserTextIdentificationFrame_fieldList(self.this); - StringList::owned(values) + pub fn values(&self) -> Option> { + let values = bridge::UserTextIdentificationFrame_fieldList(self.this.pin()); + let this = unsafe { OwnedThis::new(values) }; + this.map(|this| StringList::new(this)) } } pub struct AttachedPictureFrame<'file_ref> { - this: Pin<&'file_ref CPPID3v2AttachedPictureFrame>, + this: RefThis<'file_ref, CPPID3v2AttachedPictureFrame>, } 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 } } - pub fn picture(&self) -> ByteVector<'file_ref> { - let picture = bridge::AttachedPictureFrame_picture(self.this.as_ref()); - ByteVector::new(picture) + pub fn picture(&self) -> Option> { + let picture = bridge::AttachedPictureFrame_picture(self.this.pin()); + let this = unsafe { OwnedThis::new(picture) }; + this.map(|this| ByteVector::new(this)) } } diff --git a/musikr/src/main/jni/src/taglib/mod.rs b/musikr/src/main/jni/src/taglib/mod.rs index bcab5451d..f5d2f6fb7 100644 --- a/musikr/src/main/jni/src/taglib/mod.rs +++ b/musikr/src/main/jni/src/taglib/mod.rs @@ -10,3 +10,4 @@ pub mod mpeg; pub mod ogg; pub mod tk; pub mod xiph; +pub mod this; \ No newline at end of file diff --git a/musikr/src/main/jni/src/taglib/mpeg.rs b/musikr/src/main/jni/src/taglib/mpeg.rs index 97ad26b25..d20b6d01b 100644 --- a/musikr/src/main/jni/src/taglib/mpeg.rs +++ b/musikr/src/main/jni/src/taglib/mpeg.rs @@ -1,20 +1,21 @@ use super::bridge::{self, CPPMPEGFile}; use super::id3v2::ID3v2Tag; +use super::this::{RefThisMut, This, ThisMut}; use std::pin::Pin; pub struct MPEGFile<'file_ref> { - this: Pin<&'file_ref mut CPPMPEGFile>, + this: RefThisMut<'file_ref, CPPMPEGFile>, } 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 } } pub fn id3v2_tag(&mut self) -> Option> { - let tag = self.this.as_mut().ID3v2Tag(false); - let tag_ref = unsafe { tag.as_ref() }; - let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) }); - tag_pin.map(|tag| ID3v2Tag::new(tag)) + let tag = self.this.pin_mut().ID3v2Tag(false); + let tag_ref = unsafe { tag.as_mut() }; + let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) }); + tag_this.map(|this| ID3v2Tag::new(this)) } } diff --git a/musikr/src/main/jni/src/taglib/ogg.rs b/musikr/src/main/jni/src/taglib/ogg.rs index ae4e23b0d..57bdc9a0b 100644 --- a/musikr/src/main/jni/src/taglib/ogg.rs +++ b/musikr/src/main/jni/src/taglib/ogg.rs @@ -1,47 +1,46 @@ pub use super::bridge::{CPPOpusFile, CPPVorbisFile}; use super::xiph::XiphComment; +use super::this::{RefThisMut, RefThis, This}; use std::pin::Pin; pub struct VorbisFile<'file_ref> { - this: Pin<&'file_ref mut CPPVorbisFile>, + this: RefThisMut<'file_ref, CPPVorbisFile>, } 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 } } pub fn xiph_comments(&self) -> Option> { - let this = self.this.as_ref(); - let tag = this.vorbisTag(); + let tag = self.this.pin().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. tag.as_mut() }; - let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) }); - tag_pin.map(|tag| XiphComment::new(tag)) + let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) }); + tag_this.map(|this| XiphComment::new(this)) } } pub struct OpusFile<'file_ref> { - this: Pin<&'file_ref mut CPPOpusFile>, + this: RefThisMut<'file_ref, CPPOpusFile>, } 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 } } pub fn xiph_comments(&self) -> Option> { - let this = self.this.as_ref(); - let tag = this.opusTag(); + let tag = self.this.pin().opusTag(); 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. tag.as_mut() }; - let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) }); - tag_pin.map(|tag| XiphComment::new(tag)) + let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) }); + tag_this.map(|this| XiphComment::new(this)) } } diff --git a/musikr/src/main/jni/src/taglib/this.rs b/musikr/src/main/jni/src/taglib/this.rs new file mode 100644 index 000000000..6c03cb956 --- /dev/null +++ b/musikr/src/main/jni/src/taglib/this.rs @@ -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, +} + +impl<'file_ref, T : UniquePtrTarget> OwnedThis<'file_ref, T> { + pub unsafe fn new(this: UniquePtr) -> Option { + 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() + } +} + diff --git a/musikr/src/main/jni/src/taglib/tk.rs b/musikr/src/main/jni/src/taglib/tk.rs index 066fc3296..829751381 100644 --- a/musikr/src/main/jni/src/taglib/tk.rs +++ b/musikr/src/main/jni/src/taglib/tk.rs @@ -1,32 +1,24 @@ use super::bridge::{self, CPPByteVector, CPPString, CPPStringList}; +use super::this::{RefThis, RefThisMut, This, OwnedThis}; use cxx::{memory::UniquePtrTarget, UniquePtr}; use std::marker::PhantomData; use std::pin::Pin; use std::{ffi::CStr, string::ToString}; -enum This<'file_ref, T: UniquePtrTarget> { - Owned { - data: PhantomData<&'file_ref T>, - this: UniquePtr, - }, - Ref { - this: Pin<&'file_ref T>, - }, +pub(super) struct String<'file_ref, T: This<'file_ref, CPPString>> { + _data: PhantomData<&'file_ref ()>, + this: T, } -pub struct String<'file_ref> { - this: Pin<&'file_ref CPPString>, -} - -impl<'file_ref> String<'file_ref> { - pub(super) fn new(this: Pin<&'file_ref CPPString>) -> Self { - Self { this } +impl<'file_ref, T: This<'file_ref, CPPString>> String<'file_ref, T> { + pub(super) fn new(this: T) -> Self { + Self { _data: PhantomData, 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 { - let c_str = self.this.toCString(true); + let c_str = self.this.pin().toCString(true); unsafe { // SAFETY: // - 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> { - this: This<'file_ref, CPPStringList>, +pub type OwnedString<'file_ref> = String<'file_ref, OwnedThis<'file_ref, CPPString>>; +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(super) fn owned(this: UniquePtr) -> Self { - Self { - this: This::Owned { - data: PhantomData, - this, - }, - } - } +pub type OwnedStringList<'file_ref> = StringList<'file_ref, OwnedThis<'file_ref, CPPStringList>>; +pub type RefStringList<'file_ref> = StringList<'file_ref, RefThis<'file_ref, CPPStringList>>; +pub type RefStringListMut<'file_ref> = StringList<'file_ref, RefThisMut<'file_ref, CPPStringList>>; - pub(super) fn reference(this: Pin<&'file_ref CPPStringList>) -> Self { - Self { - this: This::Ref { this }, - } +impl<'file_ref, T: This<'file_ref, CPPStringList>> StringList<'file_ref, T> { + pub(super) fn new(this: T) -> Self { + Self { _data: PhantomData, this } } pub fn to_vec(&self) -> Vec { - let pin = match &self.this { - This::Owned { this, .. } => unsafe { Pin::new_unchecked(this.as_ref().unwrap()) }, - This::Ref { this } => *this, - }; - let cxx_values = bridge::StringList_to_vector(pin); + let cxx_values = bridge::StringList_to_vector(self.this.pin()); cxx_values .iter() .map(|value| { - let this = unsafe { Pin::new_unchecked(value) }; + let this = unsafe { RefThis::new(value) }; String::new(this).to_string() }) .collect() } } -pub struct ByteVector<'file_ref> { - // 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. +pub struct ByteVector<'file_ref, T: This<'file_ref, CPPByteVector>> { _data: PhantomData<&'file_ref CPPByteVector>, - this: UniquePtr, + this: T, } -impl<'file_ref> ByteVector<'file_ref> { - pub(super) fn new(this: UniquePtr) -> Self { - Self { - _data: PhantomData, - this, - } +impl<'file_ref, T: This<'file_ref, CPPByteVector>> ByteVector<'file_ref, T> { + pub(super) fn new(this: T) -> Self { + Self { _data: PhantomData, this } } pub fn to_vec(&self) -> Vec { - 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. - Pin::new_unchecked(this_ref) - }; + let this = self.this.pin(); let size = this.size().try_into().unwrap(); let data = this.data(); // 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>>; diff --git a/musikr/src/main/jni/src/taglib/xiph.rs b/musikr/src/main/jni/src/taglib/xiph.rs index 34e8a9a09..ac7e8a8c2 100644 --- a/musikr/src/main/jni/src/taglib/xiph.rs +++ b/musikr/src/main/jni/src/taglib/xiph.rs @@ -2,36 +2,32 @@ pub use super::bridge::CPPXiphComment; use super::bridge::{CPPFieldListMap, FieldListMap_to_entries, XiphComment_pictureList}; pub use super::flac::PictureList; use super::tk; +use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut, This}; use std::collections::HashMap; use std::pin::Pin; pub struct XiphComment<'file_ref> { - this: Pin<&'file_ref mut CPPXiphComment>, + this: RefThisMut<'file_ref, CPPXiphComment>, } 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 } } 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 - // reference. The safe API can do this, but shortens the lifecycle to at most self, even - // though the reference really lives as long as file_ref. Sadly, this requires us to transmute - // to extend the lifecycle back. This new pointer is really unsafe (we now have both a mut - // and an immutable reference to the same object), but it's dropped after this call. - // 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) }; + let map: &'slf CPPFieldListMap = self.this.pin().fieldListMap(); + // CPPFieldListMap exists for as long as the XiphComment, so we can transmute it + // to the file_ref lifetime. + let extended_map: &'file_ref CPPFieldListMap = unsafe { std::mem::transmute(map) }; + let map_pin = unsafe { Pin::new_unchecked(extended_map) }; FieldListMap::new(map_pin) } - pub fn picture_list(&mut self) -> PictureList<'file_ref> { - let pictures = XiphComment_pictureList(self.this.as_mut()); - PictureList::new(pictures) + pub fn picture_list(&mut self) -> Option> { + let pictures = XiphComment_pictureList(self.this.pin_mut()); + 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> { - pub(super) fn new(this: Pin<&'file_ref CPPFieldListMap>) -> Self { + pub fn new(this: Pin<&'file_ref CPPFieldListMap>) -> Self { Self { this } } } @@ -59,11 +55,11 @@ impl<'file_ref> FieldListMap<'file_ref> { // 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 key_this = unsafe { RefThis::new(key_ref) }; + let key = tk::String::new(key_this).to_string(); let value_ref = property_pin.value(); - let value_pin = unsafe { Pin::new_unchecked(value_ref) }; - let value = tk::StringList::reference(value_pin).to_vec(); + let value_this = unsafe { RefThis::new(value_ref) }; + let value = tk::StringList::new(value_this).to_vec(); (key, value) }) .collect()