musikr: enforce this contract

This commit is contained in:
Alexander Capehart 2025-02-17 18:55:33 -07:00
parent fc5c49081f
commit de9a60d182
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
14 changed files with 164 additions and 94 deletions

View file

@ -36,15 +36,9 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
}
pub fn set_id3v1(&mut self, tag: &id3v1::ID3v1Tag) {
if let Some(title) = tag.title() {
self.id3v2.add_id("TIT2", title.to_string());
}
if let Some(artist) = tag.artist() {
self.id3v2.add_id("TPE1", artist.to_string());
}
if let Some(album) = tag.album() {
self.id3v2.add_id("TALB", album.to_string());
}
self.id3v2.add_id("TIT2", tag.title().to_string());
self.id3v2.add_id("TPE1", tag.artist().to_string());
self.id3v2.add_id("TALB", tag.album().to_string());
self.id3v2.add_id("TRCK", tag.track().to_string());
self.id3v2.add_id("TYER", tag.year().to_string());

View file

@ -1,5 +1,11 @@
use super::iostream::DynIOStream;
pub trait TagLibAllocated {}
pub trait TagLibRef {}
pub trait TagLibShared {}
#[cxx::bridge]
mod bridge_impl {
// Expose Rust IOStream to C++
@ -86,8 +92,6 @@ mod bridge_impl {
type CPPVorbisFile;
#[cxx_name = "tag"]
fn vorbisTag(self: &CPPVorbisFile) -> *mut CPPXiphComment;
#[namespace = "taglib_shim"]
fn XiphComment_pictureList(comment: Pin<&mut CPPXiphComment>) -> UniquePtr<CPPPictureList>;
#[namespace = "TagLib::Ogg::Opus"]
#[cxx_name = "File"]
@ -133,6 +137,8 @@ mod bridge_impl {
// Explicit lifecycle definition to state while the Pin is temporary, the CPPFieldListMap
// ref returned actually has the same lifetime as the CPPXiphComment.
fn fieldListMap(self: &CPPXiphComment) -> &CPPFieldListMap;
#[namespace = "taglib_shim"]
fn XiphComment_pictureList(comment: Pin<&mut CPPXiphComment>) -> UniquePtr<CPPPictureList>;
#[namespace = "TagLib"]
#[cxx_name = "SimplePropertyMap"]
@ -316,17 +322,17 @@ mod bridge_impl {
string_list: &CPPStringList,
) -> UniquePtr<CxxVector<CPPString>>;
#[namespace = "TagLib"]
#[cxx_name = "ByteVectorList"]
type CPPByteVectorList;
#[namespace = "taglib_shim"]
fn ByteVectorList_to_vector(list: &CPPByteVectorList) -> UniquePtr<CxxVector<CPPByteVector>>;
#[namespace = "TagLib"]
#[cxx_name = "ByteVector"]
type CPPByteVector;
fn size(self: &CPPByteVector) -> u32;
fn data(self: &CPPByteVector) -> *const c_char;
#[namespace = "TagLib"]
#[cxx_name = "ByteVectorList"]
type CPPByteVectorList;
#[namespace = "taglib_shim"]
fn ByteVectorList_to_vector(list: &CPPByteVectorList) -> UniquePtr<CxxVector<CPPByteVector>>;
}
}
@ -363,3 +369,72 @@ impl MP4ItemType {
}
pub use bridge_impl::*;
impl TagLibAllocated for CPPFileRef {}
impl TagLibRef for CPPFile {}
impl TagLibRef for CppAudioProperties {}
// All of the File implementations are also TagLibRef and TagLibAllocated
impl TagLibRef for CPPVorbisFile {}
impl TagLibRef for CPPOpusFile {}
impl TagLibRef for CPPFLACFile {}
impl TagLibShared for CPPPictureList {}
impl TagLibShared for CPPFLACPicture {}
impl TagLibRef for CPPMPEGFile {}
impl TagLibRef for CPPMP4File {}
impl TagLibRef for CPPMP4Tag {}
impl TagLibRef for CPPItemMap {}
impl TagLibRef for CPPItemMapEntry {}
impl TagLibRef for CPPFieldListMap {}
impl TagLibRef for CPPFieldListEntry {}
impl TagLibRef for CPPWAVFile {}
impl TagLibRef for CPPXiphComment {}
impl TagLibRef for CPPID3v1Tag {}
impl TagLibRef for CPPID3v2Tag {}
impl TagLibShared for CPPID3v2FrameList {}
impl TagLibRef for CPPID3v2Frame {}
impl TagLibRef for CPPID3v2TextIdentificationFrame {}
impl TagLibRef for CPPID3v2UserTextIdentificationFrame {}
impl TagLibRef for CPPID3v2AttachedPictureFrame {}
impl TagLibShared for CPPMP4Item {}
impl TagLibShared for CPPCoverArt {}
impl TagLibShared for CPPIntPair {}
impl TagLibShared for CPPString {}
impl TagLibShared for CPPStringList {}
impl TagLibShared for CPPByteVector {}
impl TagLibShared for CPPByteVectorList {}
impl TagLibShared for CPPCoverArtList {}
impl<T: TagLibShared> TagLibRef for T {}
impl<T: TagLibRef> TagLibAllocated for T {}

View file

@ -29,7 +29,7 @@ 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_this = props_ref.map(|props| unsafe { RefThis::new(props) });
let props_this = props_ref.map(|props| RefThis::new(props));
props_this.map(|this| AudioProperties::new(this))
}
@ -50,7 +50,7 @@ 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_this = opus_ref.map(|opus| unsafe { RefThisMut::new(opus) });
let opus_this = opus_ref.map(|opus| RefThisMut::new(opus));
opus_this.map(|this| OpusFile::new(this))
}
@ -71,7 +71,7 @@ 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_this = vorbis_ref.map(|vorbis| unsafe { RefThisMut::new(vorbis) });
let vorbis_this = vorbis_ref.map(|vorbis| RefThisMut::new(vorbis));
vorbis_this.map(|this| VorbisFile::new(this))
}
@ -92,7 +92,7 @@ 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_this = flac_ref.map(|flac| unsafe { RefThisMut::new(flac) });
let flac_this = flac_ref.map(|flac| RefThisMut::new(flac));
flac_this.map(|this| FLACFile::new(this))
}
@ -113,7 +113,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_this = mpeg_ref.map(|mpeg| unsafe { RefThisMut::new(mpeg) });
let mpeg_this = mpeg_ref.map(|mpeg| RefThisMut::new(mpeg));
mpeg_this.map(|this| MPEGFile::new(this))
}
@ -122,7 +122,7 @@ impl<'file_ref> File<'file_ref> {
bridge::File_asMP4(self.this.ptr_mut())
};
let mp4_ref = unsafe { mp4_file.as_mut() };
let mp4_this = mp4_ref.map(|mp4| unsafe { RefThisMut::new(mp4) });
let mp4_this = mp4_ref.map(|mp4| RefThisMut::new(mp4));
mp4_this.map(|this| MP4File::new(this))
}

View file

@ -48,7 +48,7 @@ impl<'io> FileRef<'io> {
// to this, ensuring that it will not be mutated as per the aliasing rules.
file.as_mut()
});
let file_this = file_ref.map(|file| unsafe { RefThisMut::new(file) });
let file_this = file_ref.map(|file| RefThisMut::new(file));
file_this.map(|this| File::new(this))
}
}

View file

@ -27,27 +27,27 @@ impl<'file_ref> FLACFile<'file_ref> {
// via this function and thus cannot be mutated, satisfying the aliasing rules.
tag.as_mut()
};
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
let tag_this = tag_ref.map(|tag| RefThisMut::new(tag));
tag_this.map(|this| XiphComment::new(this))
}
pub fn picture_list(&mut self) -> Option<PictureList<'file_ref>> {
pub fn picture_list(&mut self) -> PictureList<'file_ref> {
let pictures = FLACFile_pictureList(self.this.pin_mut());
let this = unsafe { OwnedThis::new(pictures) };
this.map(|this| PictureList::new(this))
let this = OwnedThis::new(pictures).unwrap();
PictureList::new(this)
}
pub fn id3v1_tag(&mut self) -> Option<ID3v1Tag<'file_ref>> {
let tag = self.this.pin_mut().FLACID3v1Tag(false);
let tag_ref = unsafe { tag.as_mut() };
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
let tag_this = tag_ref.map(|tag| RefThisMut::new(tag));
tag_this.map(|this| ID3v1Tag::new(this))
}
pub fn id3v2_tag(&mut self) -> Option<ID3v2Tag<'file_ref>> {
let tag = self.this.pin_mut().FLACID3v2Tag(false);
let tag_ref = unsafe { tag.as_mut() };
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
let tag_this = tag_ref.map(|tag| RefThisMut::new(tag));
tag_this.map(|this| ID3v2Tag::new(this))
}
}
@ -71,7 +71,7 @@ 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_this = unsafe { RefThis::new(picture_ref) };
let picture_this = RefThis::new(picture_ref);
result.push(Picture::new(picture_this));
}
result
@ -87,9 +87,9 @@ impl<'file_ref> Picture<'file_ref> {
Self { this }
}
pub fn data(&self) -> Option<OwnedByteVector<'file_ref>> {
pub fn data(&self) -> OwnedByteVector<'file_ref> {
let data = Picture_data(self.this.as_ref());
let this = unsafe { OwnedThis::new(data) };
this.map(|this| ByteVector::new(this))
let this = OwnedThis::new(data).unwrap();
ByteVector::new(this)
}
}

View file

@ -11,28 +11,28 @@ impl<'file_ref> ID3v1Tag<'file_ref> {
Self { this }
}
pub fn title(&self) -> Option<OwnedString<'file_ref>> {
pub fn title(&self) -> OwnedString<'file_ref> {
let title = bridge::ID3v1Tag_title(self.this.as_ref());
let string_this = unsafe { OwnedThis::new(title) };
string_this.map(|this| String::new(this))
let this = OwnedThis::new(title).unwrap();
String::new(this)
}
pub fn artist(&self) -> Option<OwnedString<'file_ref>> {
pub fn artist(&self) -> OwnedString<'file_ref> {
let artist = bridge::ID3v1Tag_artist(self.this.as_ref());
let string_this = unsafe { OwnedThis::new(artist) };
string_this.map(|this| String::new(this))
let this = OwnedThis::new(artist).unwrap();
String::new(this)
}
pub fn album(&self) -> Option<OwnedString<'file_ref>> {
pub fn album(&self) -> OwnedString<'file_ref> {
let album = bridge::ID3v1Tag_album(self.this.as_ref());
let string_this = unsafe { OwnedThis::new(album) };
string_this.map(|this| String::new(this))
let this = OwnedThis::new(album).unwrap();
String::new(this)
}
pub fn comment(&self) -> Option<OwnedString<'file_ref>> {
pub fn comment(&self) -> OwnedString<'file_ref> {
let comment = bridge::ID3v1Tag_comment(self.this.as_ref());
let string_this = unsafe { OwnedThis::new(comment) };
string_this.map(|this| String::new(this))
let this = OwnedThis::new(comment).unwrap();
String::new(this)
}
pub fn genre_index(&self) -> u32 {

View file

@ -55,14 +55,14 @@ impl<'file_ref> Frame<'file_ref> {
pub fn id(&self) -> tk::OwnedByteVector<'file_ref> {
let id = bridge::Frame_id(self.this.as_ref());
let this = unsafe { OwnedThis::new(id).unwrap() };
let this = OwnedThis::new(id).unwrap();
ByteVector::new(this)
}
pub fn as_text_identification(&mut self) -> Option<TextIdentificationFrame<'file_ref>> {
let frame = unsafe { bridge::Frame_asTextIdentification(self.this.ptr()) };
let frame_ref = unsafe { frame.as_ref() };
let frame_this = frame_ref.map(|frame| unsafe { RefThis::new(frame) });
let frame_this = frame_ref.map(|frame| RefThis::new(frame));
frame_this.map(|this| TextIdentificationFrame::new(this))
}
@ -71,14 +71,14 @@ impl<'file_ref> Frame<'file_ref> {
) -> Option<UserTextIdentificationFrame<'file_ref>> {
let frame = unsafe { bridge::Frame_asUserTextIdentification(self.this.ptr()) };
let frame_ref = unsafe { frame.as_ref() };
let frame_this = frame_ref.map(|frame| unsafe { RefThis::new(frame) });
let frame_this = frame_ref.map(|frame| RefThis::new(frame));
frame_this.map(|this| UserTextIdentificationFrame::new(this))
}
pub fn as_attached_picture(&mut self) -> Option<AttachedPictureFrame<'file_ref>> {
let frame = unsafe { bridge::Frame_asAttachedPicture(self.this.ptr()) };
let frame_ref = unsafe { frame.as_ref() };
let frame_this = frame_ref.map(|frame| unsafe { RefThis::new(frame) });
let frame_this = frame_ref.map(|frame| RefThis::new(frame));
frame_this.map(|this| AttachedPictureFrame::new(this))
}
}

View file

@ -16,11 +16,11 @@ impl<'file_ref> MP4File<'file_ref> {
pub fn tag(&self) -> Option<MP4Tag<'file_ref>> {
let this = self.this.as_ref();
let tag = unsafe { this.MP4Tag() };
let tag = this.MP4Tag();
let tag_ref = unsafe { tag.as_ref() };
tag_ref.map(|tag| {
// SAFETY: The tag pointer is guaranteed to be valid for the lifetime of self
let tag_this = unsafe { RefThis::new(tag) };
let tag_this = RefThis::new(tag);
MP4Tag::new(tag_this)
})
}
@ -37,7 +37,7 @@ impl<'file_ref> MP4Tag<'file_ref> {
pub fn item_map(&'file_ref self) -> ItemMap<'file_ref> {
let map: &'file_ref CPPItemMap = self.this.as_ref().itemMap();
let map_this = unsafe { RefThis::new(map) };
let map_this = RefThis::new(map);
ItemMap::new(map_this)
}
}
@ -63,11 +63,11 @@ impl<'file_ref> ItemMap<'file_ref> {
// - The values returned are copied and thus not dependent on the address
// of self.
let key_ref = property.key();
let key_this = unsafe { OwnedThis::new(key_ref) }.unwrap();
let key_this = OwnedThis::new(key_ref).unwrap();
let key = tk::String::new(key_this).to_string();
let value_ref = property.value();
let value_this = unsafe { OwnedThis::new(value_ref) }.unwrap();
let value_this = OwnedThis::new(value_ref).unwrap();
let value = MP4Item::new(value_this);
(key, value)
@ -99,26 +99,26 @@ impl<'file_ref> MP4Item<'file_ref> {
MP4ItemType::Int => Some(MP4Data::Int(self.this.as_ref().toInt())),
MP4ItemType::IntPair => {
let pair = super::bridge::Item_toIntPair(self.this.as_ref());
let pair_this = unsafe { OwnedThis::new(pair) };
pair_this.map(|this| MP4Data::IntPair(IntPair::new(this)))
let pair_this = OwnedThis::new(pair).unwrap();
Some(MP4Data::IntPair(IntPair::new(pair_this)))
},
MP4ItemType::Byte => Some(MP4Data::Byte(self.this.as_ref().toByte())),
MP4ItemType::UInt => Some(MP4Data::UInt(self.this.as_ref().toUInt())),
MP4ItemType::LongLong => Some(MP4Data::LongLong(super::bridge::Item_toLongLong(self.this.as_ref()))),
MP4ItemType::StringList => {
let string_list = super::bridge::Item_toStringList(self.this.as_ref());
let string_list_this = unsafe { OwnedThis::new(string_list) };
string_list_this.map(|this| MP4Data::StringList(tk::StringList::new(this)))
let string_list_this = OwnedThis::new(string_list).unwrap();
Some(MP4Data::StringList(tk::StringList::new(string_list_this)))
},
MP4ItemType::ByteVectorList => {
let byte_vector_list = super::bridge::Item_toByteVectorList(self.this.as_ref());
let byte_vector_list_this = unsafe { OwnedThis::new(byte_vector_list) };
byte_vector_list_this.map(|this| MP4Data::ByteVectorList(tk::ByteVectorList::new(this)))
let byte_vector_list_this = OwnedThis::new(byte_vector_list).unwrap();
Some(MP4Data::ByteVectorList(tk::ByteVectorList::new(byte_vector_list_this)))
},
MP4ItemType::CoverArtList => {
let cover_art_list = super::bridge::Item_toCoverArtList(self.this.as_ref());
let cover_art_list_this = unsafe { OwnedThis::new(cover_art_list) };
cover_art_list_this.map(|this| MP4Data::CoverArtList(CoverArtList::new(this)))
let cover_art_list_this = OwnedThis::new(cover_art_list).unwrap();
Some(MP4Data::CoverArtList(CoverArtList::new(cover_art_list_this)))
}
})
}

View file

@ -16,14 +16,14 @@ impl<'file_ref> MPEGFile<'file_ref> {
pub fn id3v1_tag(&mut self) -> Option<ID3v1Tag<'file_ref>> {
let tag = self.this.pin_mut().MPEGID3v1Tag(false);
let tag_ref = unsafe { tag.as_mut() };
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
let tag_this = tag_ref.map(|tag| RefThisMut::new(tag));
tag_this.map(|this| ID3v1Tag::new(this))
}
pub fn id3v2_tag(&mut self) -> Option<ID3v2Tag<'file_ref>> {
let tag = self.this.pin_mut().MPEGID3v2Tag(false);
let tag_ref = unsafe { tag.as_mut() };
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
let tag_this = tag_ref.map(|tag| RefThisMut::new(tag));
tag_this.map(|this| ID3v2Tag::new(this))
}
}

View file

@ -19,7 +19,7 @@ impl<'file_ref> VorbisFile<'file_ref> {
// via this function and thus cannot be mutated, satisfying the aliasing rules.
tag.as_mut()
};
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
let tag_this = tag_ref.map(|tag| RefThisMut::new(tag));
tag_this.map(|this| XiphComment::new(this))
}
}
@ -40,7 +40,7 @@ impl<'file_ref> OpusFile<'file_ref> {
// via this function and thus cannot be mutated, satisfying the aliasing rules.
tag.as_mut()
};
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
let tag_this = tag_ref.map(|tag| RefThisMut::new(tag));
tag_this.map(|this| XiphComment::new(this))
}
}

View file

@ -15,7 +15,7 @@ impl<'file_ref> WAVFile<'file_ref> {
pub fn id3v2_tag(&mut self) -> Option<ID3v2Tag<'file_ref>> {
let tag = self.this.as_ref().WAVID3v2Tag();
let tag_ref = unsafe { tag.as_mut() };
let tag_this = tag_ref.map(|tag| unsafe { RefThisMut::new(tag) });
let tag_this = tag_ref.map(|tag| RefThisMut::new(tag));
tag_this.map(|this| ID3v2Tag::new(this))
}
}

View file

@ -1,6 +1,7 @@
use std::marker::PhantomData;
use std::pin::Pin;
use cxx::{UniquePtr, memory::UniquePtrTarget};
use super::bridge::{TagLibAllocated, TagLibRef, TagLibShared};
/// A taglib-FFI-specific trait representing a C++ object returned by the library.
///
@ -9,7 +10,7 @@ use cxx::{UniquePtr, memory::UniquePtrTarget};
/// and will be dropped when the FileRef is dropped.
/// - This object will not move or be mutated over the FileRef's lifetime, this way
/// it can be temporarily pinned for use as a `this` pointer.
pub trait This<'file_ref, T> : AsRef<T> {}
pub trait This<'file_ref, T: TagLibAllocated> : AsRef<T> {}
/// A taglib-FFI-specific trait representing a C++ object returned by the library.
///
@ -21,16 +22,16 @@ pub trait This<'file_ref, T> : AsRef<T> {}
/// and will be dropped when the FileRef is dropped.
/// - This object will not move over the FileRef's lifetime, this way it can be
/// temporarily pinned for use as a `this` pointer.
pub trait ThisMut<'file_ref, T> : This<'file_ref, T> {
pub trait ThisMut<'file_ref, T: TagLibAllocated> : This<'file_ref, T> {
fn pin_mut(&mut self) -> Pin<&mut T>;
}
/// A [This] instance that is a reference to a C++ object.
pub struct RefThis<'file_ref, T> {
pub struct RefThis<'file_ref, T: TagLibRef> {
this: &'file_ref T
}
impl<'file_ref, T> RefThis<'file_ref, T> {
impl<'file_ref, T: TagLibRef> RefThis<'file_ref, T> {
/// Create a new [RefThis] from a reference to a C++ object.
///
/// This is safe to call assuming the contract of [This] is upheld. Since this
@ -38,7 +39,7 @@ impl<'file_ref, T> RefThis<'file_ref, T> {
/// responsibility to ensure that the reference is valid for the lifetime of
/// the `'file_ref` parameter. More or less, if it comes from the TagLib FFI
/// interface, it is safe to use this.
pub unsafe fn new(this: &'file_ref T) -> Self {
pub 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 }
@ -54,22 +55,22 @@ impl<'file_ref, T> RefThis<'file_ref, T> {
}
}
impl<'file_ref, T> AsRef<T> for RefThis<'file_ref, T> {
impl<'file_ref, T: TagLibRef> AsRef<T> for RefThis<'file_ref, T> {
fn as_ref(&self) -> &T {
self.this
}
}
impl<'file_ref, T> This<'file_ref, T> for RefThis<'file_ref, T> {}
impl<'file_ref, T: TagLibRef> This<'file_ref, T> for RefThis<'file_ref, T> {}
/// A [ThisMut] instance that is a reference to a C++ object.
///
/// This is similar to [RefThis], but allows mutating the object.
pub struct RefThisMut<'file_ref, T> {
pub struct RefThisMut<'file_ref, T: TagLibRef> {
this: &'file_ref mut T,
}
impl<'file_ref, T> RefThisMut<'file_ref, T> {
impl<'file_ref, T: TagLibRef> RefThisMut<'file_ref, T> {
/// Create a new [RefThisMut] from a reference to a C++ object.
///
/// This is safe to call assuming the contract of [ThisMut] is upheld. Since
@ -77,7 +78,7 @@ impl<'file_ref, T> RefThisMut<'file_ref, T> {
/// responsibility to ensure that the reference is valid for the lifetime of
/// the `'file_ref` parameter. More or less, if it comes from the TagLib FFI
/// interface, it is safe to use this.
pub unsafe fn new(this: &'file_ref mut T) -> Self {
pub fn new(this: &'file_ref mut T) -> Self {
Self { this }
}
@ -100,15 +101,15 @@ impl<'file_ref, T> RefThisMut<'file_ref, T> {
}
}
impl<'file_ref, T> AsRef<T> for RefThisMut<'file_ref, T> {
impl<'file_ref, T: TagLibRef> AsRef<T> for RefThisMut<'file_ref, T> {
fn as_ref(&self) -> &T {
self.this
}
}
impl<'file_ref, T> This<'file_ref, T> for RefThisMut<'file_ref, T> {}
impl<'file_ref, T: TagLibRef> This<'file_ref, T> for RefThisMut<'file_ref, T> {}
impl<'file_ref, T> ThisMut<'file_ref, T> for RefThisMut<'file_ref, T> {
impl<'file_ref, T: TagLibRef> ThisMut<'file_ref, T> for RefThisMut<'file_ref, T> {
fn pin_mut(&mut self) -> Pin<&mut T> {
unsafe { Pin::new_unchecked(self.this) }
}
@ -119,12 +120,12 @@ impl<'file_ref, T> ThisMut<'file_ref, T> for RefThisMut<'file_ref, T> {
/// "Owned" in this context only really means that the object is not a rust reference.
/// In practice, all "owned" taglib objects are actually shared references, and are
/// thus tied to the lifetime of the `'file_ref` parameter.
pub struct OwnedThis<'file_ref, T : UniquePtrTarget> {
pub struct OwnedThis<'file_ref, T: TagLibShared + UniquePtrTarget> {
_data: PhantomData<&'file_ref ()>,
this: UniquePtr<T>,
}
impl<'file_ref, T : UniquePtrTarget> OwnedThis<'file_ref, T> {
impl<'file_ref, T: TagLibShared + UniquePtrTarget> OwnedThis<'file_ref, T> {
/// Create a new [OwnedThis] from a [UniquePtr].
///
/// This is safe to call assuming the contract of [This] is upheld. Since this
@ -134,7 +135,7 @@ impl<'file_ref, T : UniquePtrTarget> OwnedThis<'file_ref, T> {
/// interface, it is safe to use this.
///
/// This will return `None` if the `UniquePtr` is `null`.
pub unsafe fn new(this: UniquePtr<T>) -> Option<Self> {
pub fn new(this: UniquePtr<T>) -> Option<Self> {
if !this.is_null() {
Some(Self {
_data: PhantomData,
@ -146,15 +147,15 @@ impl<'file_ref, T : UniquePtrTarget> OwnedThis<'file_ref, T> {
}
}
impl<'file_ref, T : UniquePtrTarget> AsRef<T> for OwnedThis<'file_ref, T> {
impl<'file_ref, T: TagLibShared + UniquePtrTarget> AsRef<T> for OwnedThis<'file_ref, T> {
fn as_ref(&self) -> &T {
self.this.as_ref().unwrap()
}
}
impl<'file_ref, T : UniquePtrTarget> This<'file_ref, T> for OwnedThis<'file_ref, T> {}
impl<'file_ref, T: TagLibShared + UniquePtrTarget> This<'file_ref, T> for OwnedThis<'file_ref, T> {}
impl<'file_ref, T : UniquePtrTarget> ThisMut<'file_ref, T> for OwnedThis<'file_ref, T> {
impl<'file_ref, T: TagLibShared + UniquePtrTarget> ThisMut<'file_ref, T> for OwnedThis<'file_ref, T> {
fn pin_mut(&mut self) -> Pin<&mut T> {
self.this.as_mut().unwrap()
}

View file

@ -63,7 +63,7 @@ impl<'file_ref, T: This<'file_ref, InnerStringList>> StringList<'file_ref, T> {
cxx_values
.iter()
.map(|value| {
let this = unsafe { RefThis::new(value) };
let this = RefThis::new(value);
String::new(this).to_string()
})
.collect()

View file

@ -17,14 +17,14 @@ impl<'file_ref> XiphComment<'file_ref> {
pub fn field_list_map(&'file_ref self) -> FieldListMap<'file_ref> {
let map: &'file_ref CPPFieldListMap = self.this.as_ref().fieldListMap();
let map_this = unsafe { RefThis::new(map) };
let map_this = RefThis::new(map);
FieldListMap::new(map_this)
}
pub fn picture_list(&mut self) -> Option<PictureList<'file_ref>> {
pub fn picture_list(&mut self) -> PictureList<'file_ref> {
let pictures = XiphComment_pictureList(self.this.pin_mut());
let pictures_this = unsafe { OwnedThis::new(pictures) };
pictures_this.map(|this| PictureList::new(this))
let pictures_this = OwnedThis::new(pictures).unwrap();
PictureList::new(pictures_this)
}
}
@ -51,10 +51,10 @@ impl<'file_ref> FieldListMap<'file_ref> {
// - The values returned are copied and thus not dependent on the address
// of self.
let key_ref = property.key();
let key_this = unsafe { OwnedThis::new(key_ref) }.unwrap();
let key_this = OwnedThis::new(key_ref).unwrap();
let key = tk::String::new(key_this).to_string();
let value_ref = property.value();
let value_this = unsafe { OwnedThis::new(value_ref) }.unwrap();
let value_this = OwnedThis::new(value_ref).unwrap();
let value = tk::StringList::new(value_this);
(key, value)
})