musikr: add id3v2 tags
This commit is contained in:
parent
0f3bed413d
commit
f7d61cd1dc
11 changed files with 325 additions and 51 deletions
|
@ -121,6 +121,7 @@ fn main() {
|
|||
.file("shim/tk_shim.cpp")
|
||||
.file("shim/picture_shim.cpp")
|
||||
.file("shim/xiph_shim.cpp")
|
||||
.file("shim/id3_shim.cpp")
|
||||
.include(format!("taglib/pkg/{}/include", target))
|
||||
.include(".") // Add the current directory to include path
|
||||
.flag_if_supported("-std=c++14");
|
||||
|
|
39
musikr/src/main/jni/shim/id3_shim.cpp
Normal file
39
musikr/src/main/jni/shim/id3_shim.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "id3_shim.hpp"
|
||||
|
||||
namespace taglib_shim {
|
||||
const TagLib::ID3v2::TextIdentificationFrame* Frame_asTextIdentification(const TagLib::ID3v2::Frame* frame) {
|
||||
return dynamic_cast<const TagLib::ID3v2::TextIdentificationFrame*>(frame);
|
||||
}
|
||||
|
||||
const TagLib::ID3v2::UserTextIdentificationFrame* Frame_asUserTextIdentification(const TagLib::ID3v2::Frame* frame) {
|
||||
return dynamic_cast<const TagLib::ID3v2::UserTextIdentificationFrame*>(frame);
|
||||
}
|
||||
|
||||
const TagLib::ID3v2::AttachedPictureFrame* Frame_asAttachedPicture(const TagLib::ID3v2::Frame* frame) {
|
||||
return dynamic_cast<const TagLib::ID3v2::AttachedPictureFrame*>(frame);
|
||||
}
|
||||
|
||||
std::unique_ptr<TagLib::ByteVector> AttachedPictureFrame_picture(const TagLib::ID3v2::AttachedPictureFrame& frame) {
|
||||
return std::make_unique<TagLib::ByteVector>(frame.picture());
|
||||
}
|
||||
|
||||
std::unique_ptr<TagLib::StringList> TextIdentificationFrame_fieldList(const TagLib::ID3v2::TextIdentificationFrame& frame) {
|
||||
return std::make_unique<TagLib::StringList>(frame.fieldList());
|
||||
}
|
||||
|
||||
std::unique_ptr<TagLib::StringList> UserTextIdentificationFrame_fieldList(const TagLib::ID3v2::UserTextIdentificationFrame& frame) {
|
||||
return std::make_unique<TagLib::StringList>(frame.fieldList());
|
||||
}
|
||||
|
||||
TagLib::ID3v2::Tag* File_ID3v2Tag(TagLib::MPEG::File* file, bool create) {
|
||||
return file->ID3v2Tag(create);
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<WrappedFrame>> Tag_frameList(const TagLib::ID3v2::Tag& tag) {
|
||||
auto frames = std::make_unique<std::vector<WrappedFrame>>();
|
||||
for (const auto& frame : tag.frameList()) {
|
||||
frames->push_back(WrappedFrame{frame});
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
}
|
31
musikr/src/main/jni/shim/id3_shim.hpp
Normal file
31
musikr/src/main/jni/shim/id3_shim.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "rust/cxx.h"
|
||||
#include "taglib/id3v2tag.h"
|
||||
#include "taglib/id3v2frame.h"
|
||||
#include "taglib/textidentificationframe.h"
|
||||
#include "taglib/unsynchronizedlyricsframe.h"
|
||||
#include "taglib/attachedpictureframe.h"
|
||||
#include "taglib/tbytevector.h"
|
||||
#include "taglib/mpegfile.h"
|
||||
|
||||
namespace taglib_shim {
|
||||
struct WrappedFrame {
|
||||
const TagLib::ID3v2::Frame* inner;
|
||||
const TagLib::ID3v2::Frame* get() const { return inner; }
|
||||
};
|
||||
|
||||
// Frame type checking and casting
|
||||
const TagLib::ID3v2::TextIdentificationFrame* Frame_asTextIdentification(const TagLib::ID3v2::Frame* frame);
|
||||
const TagLib::ID3v2::UserTextIdentificationFrame* Frame_asUserTextIdentification(const TagLib::ID3v2::Frame* frame);
|
||||
const TagLib::ID3v2::AttachedPictureFrame* Frame_asAttachedPicture(const TagLib::ID3v2::Frame* frame);
|
||||
|
||||
// Frame data access
|
||||
std::unique_ptr<TagLib::ByteVector> AttachedPictureFrame_picture(const TagLib::ID3v2::AttachedPictureFrame& frame);
|
||||
std::unique_ptr<TagLib::StringList> TextIdentificationFrame_fieldList(const TagLib::ID3v2::TextIdentificationFrame& frame);
|
||||
std::unique_ptr<TagLib::StringList> UserTextIdentificationFrame_fieldList(const TagLib::ID3v2::UserTextIdentificationFrame& frame);
|
||||
|
||||
// ID3v2 tag access
|
||||
TagLib::ID3v2::Tag* File_ID3v2Tag(TagLib::MPEG::File* file, bool create);
|
||||
std::unique_ptr<std::vector<WrappedFrame>> Tag_frameList(const TagLib::ID3v2::Tag& tag);
|
||||
}
|
|
@ -8,7 +8,6 @@ mod taglib;
|
|||
mod jstream;
|
||||
|
||||
use taglib::file_ref::FileRef;
|
||||
use taglib::file::File;
|
||||
use jstream::JInputStream;
|
||||
|
||||
type SharedEnv<'local> = Rc<RefCell<JNIEnv<'local>>>;
|
||||
|
|
|
@ -32,6 +32,8 @@ mod bridge_impl {
|
|||
include!("shim/tk_shim.hpp");
|
||||
include!("shim/picture_shim.hpp");
|
||||
include!("shim/xiph_shim.hpp");
|
||||
include!("shim/id3_shim.hpp");
|
||||
include!("taglib/mpegfile.h");
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "IOStream"]
|
||||
|
@ -55,6 +57,18 @@ mod bridge_impl {
|
|||
type CPPFile;
|
||||
#[cxx_name = "audioProperties"]
|
||||
fn audioProperties(self: Pin<&CPPFile>) -> *mut CppAudioProperties;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asVorbis(file: *mut CPPFile) -> *mut CPPVorbisFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asOpus(file: *mut CPPFile) -> *mut CPPOpusFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asMPEG(file: *mut CPPFile) -> *mut CPPMPEGFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asFLAC(file: *mut CPPFile) -> *mut CPPFLACFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asMP4(file: *mut CPPFile) -> *mut CPPMP4File;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asWAV(file: *mut CPPFile) -> *mut CPPWAVFile;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "AudioProperties"]
|
||||
|
@ -68,34 +82,6 @@ mod bridge_impl {
|
|||
#[cxx_name = "channels"]
|
||||
fn channels(self: Pin<&CppAudioProperties>) -> i32;
|
||||
|
||||
#[namespace = "TagLib::FLAC"]
|
||||
#[cxx_name = "Picture"]
|
||||
type CPPFLACPicture;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn Picture_data(picture: Pin<&CPPFLACPicture>) -> UniquePtr<CPPByteVector>;
|
||||
|
||||
#[namespace = "TagLib::Ogg"]
|
||||
#[cxx_name = "XiphComment"]
|
||||
type CPPXiphComment;
|
||||
#[cxx_name = "fieldListMap"]
|
||||
fn fieldListMap(self: Pin<& CPPXiphComment>) -> &CPPFieldListMap;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "SimplePropertyMap"]
|
||||
type CPPFieldListMap;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn FieldListMap_to_entries(
|
||||
field_list_map: Pin<&CPPFieldListMap>,
|
||||
) -> UniquePtr<CxxVector<CPPFieldListEntry>>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
#[cxx_name = "FieldListEntry"]
|
||||
type CPPFieldListEntry;
|
||||
#[cxx_name = "key"]
|
||||
fn key(self: Pin<&CPPFieldListEntry>) -> &CPPString;
|
||||
#[cxx_name = "value"]
|
||||
fn value(self: Pin<&CPPFieldListEntry>) -> &CPPStringList;
|
||||
|
||||
#[namespace = "TagLib::Ogg::Vorbis"]
|
||||
#[cxx_name = "File"]
|
||||
type CPPVorbisFile;
|
||||
|
@ -132,6 +118,8 @@ mod bridge_impl {
|
|||
#[namespace = "TagLib::MPEG"]
|
||||
#[cxx_name = "File"]
|
||||
type CPPMPEGFile;
|
||||
#[cxx_name = "ID3v2Tag"]
|
||||
fn ID3v2Tag(self: Pin<&mut CPPMPEGFile>, create: bool) -> *mut CPPID3v2Tag;
|
||||
|
||||
#[namespace = "TagLib::MP4"]
|
||||
#[cxx_name = "File"]
|
||||
|
@ -141,18 +129,71 @@ mod bridge_impl {
|
|||
#[cxx_name = "File"]
|
||||
type CPPWAVFile;
|
||||
|
||||
#[namespace = "TagLib::FLAC"]
|
||||
#[cxx_name = "Picture"]
|
||||
type CPPFLACPicture;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asVorbis(file: *mut CPPFile) -> *mut CPPVorbisFile;
|
||||
fn Picture_data(picture: Pin<&CPPFLACPicture>) -> UniquePtr<CPPByteVector>;
|
||||
|
||||
#[namespace = "TagLib::Ogg"]
|
||||
#[cxx_name = "XiphComment"]
|
||||
type CPPXiphComment;
|
||||
#[cxx_name = "fieldListMap"]
|
||||
fn fieldListMap(self: Pin<& CPPXiphComment>) -> &CPPFieldListMap;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "SimplePropertyMap"]
|
||||
type CPPFieldListMap;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asOpus(file: *mut CPPFile) -> *mut CPPOpusFile;
|
||||
fn FieldListMap_to_entries(
|
||||
field_list_map: Pin<&CPPFieldListMap>,
|
||||
) -> UniquePtr<CxxVector<CPPFieldListEntry>>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asMPEG(file: *mut CPPFile) -> *mut CPPMPEGFile;
|
||||
#[cxx_name = "FieldListEntry"]
|
||||
type CPPFieldListEntry;
|
||||
#[cxx_name = "key"]
|
||||
fn key(self: Pin<&CPPFieldListEntry>) -> &CPPString;
|
||||
#[cxx_name = "value"]
|
||||
fn value(self: Pin<&CPPFieldListEntry>) -> &CPPStringList;
|
||||
|
||||
#[namespace = "TagLib::ID3v2"]
|
||||
#[cxx_name = "Tag"]
|
||||
type CPPID3v2Tag;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asFLAC(file: *mut CPPFile) -> *mut CPPFLACFile;
|
||||
fn Tag_frameList(tag: Pin<&CPPID3v2Tag>) -> UniquePtr<CxxVector<WrappedFrame>>;
|
||||
|
||||
#[namespace = "TagLib::ID3v2"]
|
||||
#[cxx_name = "Frame"]
|
||||
type CPPID3v2Frame;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asMP4(file: *mut CPPFile) -> *mut CPPMP4File;
|
||||
unsafe fn Frame_asTextIdentification(frame: *const CPPID3v2Frame) -> *const CPPID3v2TextIdentificationFrame;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asWAV(file: *mut CPPFile) -> *mut CPPWAVFile;
|
||||
unsafe fn Frame_asUserTextIdentification(frame: *const CPPID3v2Frame) -> *const CPPID3v2UserTextIdentificationFrame;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn Frame_asAttachedPicture(frame: *const CPPID3v2Frame) -> *const CPPID3v2AttachedPictureFrame;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
type WrappedFrame;
|
||||
fn get(self: &WrappedFrame) -> *const CPPID3v2Frame;
|
||||
|
||||
#[namespace = "TagLib::ID3v2"]
|
||||
#[cxx_name = "TextIdentificationFrame"]
|
||||
type CPPID3v2TextIdentificationFrame;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn TextIdentificationFrame_fieldList(frame: Pin<&CPPID3v2TextIdentificationFrame>) -> UniquePtr<CPPStringList>;
|
||||
|
||||
#[namespace = "TagLib::ID3v2"]
|
||||
#[cxx_name = "UserTextIdentificationFrame"]
|
||||
type CPPID3v2UserTextIdentificationFrame;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn UserTextIdentificationFrame_fieldList(frame: Pin<&CPPID3v2UserTextIdentificationFrame>) -> UniquePtr<CPPStringList>;
|
||||
|
||||
#[namespace = "TagLib::ID3v2"]
|
||||
#[cxx_name = "AttachedPictureFrame"]
|
||||
type CPPID3v2AttachedPictureFrame;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn AttachedPictureFrame_picture(frame: Pin<&CPPID3v2AttachedPictureFrame>) -> UniquePtr<CPPByteVector>;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "String"]
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
use std::pin::Pin;
|
||||
use super::bridge::{self, CPPFile};
|
||||
use super::bridge::{self, CPPFile, CPPMPEGFile};
|
||||
use super::audioproperties::AudioProperties;
|
||||
use super::mpeg::MPEGFile;
|
||||
use super::ogg::OpusFile;
|
||||
use super::ogg::VorbisFile;
|
||||
use super::flac::FLACFile;
|
||||
use super::id3::Tag;
|
||||
|
||||
pub struct File<'file_ref> {
|
||||
this: Pin<&'file_ref mut CPPFile>
|
||||
}
|
||||
|
||||
|
||||
impl<'file_ref> File<'file_ref> {
|
||||
pub(super) fn new(this: Pin<&'file_ref mut CPPFile>) -> Self {
|
||||
Self { this }
|
||||
|
@ -92,12 +93,25 @@ impl<'file_ref> File<'file_ref> {
|
|||
let flac_pin = flac_ref.map(|flac| unsafe { Pin::new_unchecked(flac) });
|
||||
flac_pin.map(|flac| FLACFile::new(flac))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'file_ref> Drop for File<'file_ref> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
std::ptr::drop_in_place(&mut self.this);
|
||||
}
|
||||
pub fn as_mpeg(&mut self) -> Option<MPEGFile<'file_ref>> {
|
||||
let mpeg_file = unsafe {
|
||||
// SAFETY:
|
||||
// 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)
|
||||
};
|
||||
let mpeg_ref = unsafe {
|
||||
// SAFETY:
|
||||
// - This points to a C++ FFI type ensured to be aligned by cxx's codegen.
|
||||
// - The null-safe version is being used.
|
||||
// - This points to a C++FFI type ensured to be valid by cxx's codegen.
|
||||
// - There are no datapaths that will yield any mutable pointers or references
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
108
musikr/src/main/jni/src/taglib/id3.rs
Normal file
108
musikr/src/main/jni/src/taglib/id3.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
use super::bridge::{
|
||||
self, CPPID3v2Frame, CPPID3v2TextIdentificationFrame,
|
||||
CPPID3v2UserTextIdentificationFrame, CPPID3v2AttachedPictureFrame, CPPID3v2Tag
|
||||
};
|
||||
use super::tk::{ByteVector, StringList};
|
||||
use std::pin::Pin;
|
||||
|
||||
pub struct Tag<'file_ref> {
|
||||
this: Pin<&'file_ref CPPID3v2Tag>
|
||||
}
|
||||
|
||||
impl<'file_ref> Tag<'file_ref> {
|
||||
pub(super) fn new(this: Pin<&'file_ref CPPID3v2Tag>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
|
||||
pub fn frames(&self) -> Vec<Frame<'file_ref>> {
|
||||
let frames = bridge::Tag_frameList(self.this.as_ref());
|
||||
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)
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Frame<'file_ref> {
|
||||
this: Pin<&'file_ref CPPID3v2Frame>
|
||||
}
|
||||
|
||||
impl<'file_ref> Frame<'file_ref> {
|
||||
pub(super) fn new(this: Pin<&'file_ref CPPID3v2Frame>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
|
||||
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_ref = unsafe { frame.as_ref() };
|
||||
let frame_pin = frame_ref.map(|frame| unsafe { Pin::new_unchecked(frame) });
|
||||
frame_pin.map(|frame| TextIdentificationFrame::new(frame))
|
||||
}
|
||||
|
||||
pub fn as_user_text_identification(&mut self) -> Option<UserTextIdentificationFrame<'file_ref>> {
|
||||
let frame = unsafe {
|
||||
bridge::Frame_asUserTextIdentification(self.this.as_ref().get_ref())
|
||||
};
|
||||
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))
|
||||
}
|
||||
|
||||
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_ref = unsafe { frame.as_ref() };
|
||||
let frame_pin = frame_ref.map(|frame| unsafe { Pin::new_unchecked(frame) });
|
||||
frame_pin.map(|frame| AttachedPictureFrame::new(frame))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextIdentificationFrame<'file_ref> {
|
||||
this: Pin<&'file_ref CPPID3v2TextIdentificationFrame>
|
||||
}
|
||||
|
||||
impl<'file_ref> TextIdentificationFrame<'file_ref> {
|
||||
pub(super) fn new(this: Pin<&'file_ref CPPID3v2TextIdentificationFrame>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
|
||||
pub fn field_list<'slf>(&'slf self) -> StringList<'file_ref> {
|
||||
let field_list = bridge::TextIdentificationFrame_fieldList(self.this);
|
||||
StringList::owned(field_list)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserTextIdentificationFrame<'file_ref> {
|
||||
this: Pin<&'file_ref CPPID3v2UserTextIdentificationFrame>
|
||||
}
|
||||
|
||||
impl<'file_ref> UserTextIdentificationFrame<'file_ref> {
|
||||
pub(super) fn new(this: Pin<&'file_ref CPPID3v2UserTextIdentificationFrame>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
|
||||
pub fn values<'slf>(&'slf self) -> StringList<'file_ref> {
|
||||
let values = bridge::UserTextIdentificationFrame_fieldList(self.this);
|
||||
StringList::owned(values)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AttachedPictureFrame<'file_ref> {
|
||||
this: Pin<&'file_ref CPPID3v2AttachedPictureFrame>
|
||||
}
|
||||
|
||||
impl<'file_ref> AttachedPictureFrame<'file_ref> {
|
||||
pub(super) fn new(this: Pin<&'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)
|
||||
}
|
||||
}
|
|
@ -7,4 +7,6 @@ pub mod audioproperties;
|
|||
pub mod ogg;
|
||||
pub mod flac;
|
||||
pub mod xiph;
|
||||
pub mod tk;
|
||||
pub mod mpeg;
|
||||
pub mod tk;
|
||||
pub mod id3;
|
20
musikr/src/main/jni/src/taglib/mpeg.rs
Normal file
20
musikr/src/main/jni/src/taglib/mpeg.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use std::pin::Pin;
|
||||
use super::bridge::{self, CPPMPEGFile};
|
||||
use super::id3::Tag;
|
||||
|
||||
pub struct MPEGFile<'file_ref> {
|
||||
this: Pin<&'file_ref mut CPPMPEGFile>
|
||||
}
|
||||
|
||||
impl<'file_ref> MPEGFile<'file_ref> {
|
||||
pub(super) fn new(this: Pin<&'file_ref mut CPPMPEGFile>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
|
||||
pub fn id3v2_tag(&mut self) -> Option<Tag<'file_ref>> {
|
||||
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| Tag::new(tag))
|
||||
}
|
||||
}
|
|
@ -1,9 +1,19 @@
|
|||
use super::bridge::{self, CPPByteVector, CPPString, CPPStringList};
|
||||
use cxx::UniquePtr;
|
||||
use cxx::{UniquePtr, memory::UniquePtrTarget};
|
||||
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<T>,
|
||||
},
|
||||
Ref {
|
||||
this: Pin<&'file_ref T>,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct String<'file_ref> {
|
||||
this: Pin<&'file_ref CPPString>,
|
||||
}
|
||||
|
@ -14,6 +24,7 @@ impl<'file_ref> String<'file_ref> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'file_ref> ToString for String<'file_ref> {
|
||||
fn to_string(&self) -> std::string::String {
|
||||
let c_str = self.this.toCString(true);
|
||||
|
@ -35,16 +46,24 @@ impl<'file_ref> ToString for String<'file_ref> {
|
|||
}
|
||||
|
||||
pub struct StringList<'file_ref> {
|
||||
this: Pin<&'file_ref CPPStringList>,
|
||||
this: This<'file_ref, CPPStringList>,
|
||||
}
|
||||
|
||||
impl<'file_ref> StringList<'file_ref> {
|
||||
pub(super) fn new(this: Pin<&'file_ref CPPStringList>) -> Self {
|
||||
Self { this }
|
||||
pub(super) fn owned(this: UniquePtr<CPPStringList>) -> Self {
|
||||
Self { this: This::Owned { data: PhantomData, this } }
|
||||
}
|
||||
|
||||
pub(super) fn reference(this: Pin<&'file_ref CPPStringList>) -> Self {
|
||||
Self { this: This::Ref { this } }
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<std::string::String> {
|
||||
let cxx_values = bridge::StringList_to_vector(self.this);
|
||||
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);
|
||||
cxx_values
|
||||
.iter()
|
||||
.map(|value| {
|
||||
|
|
|
@ -63,7 +63,7 @@ impl<'file_ref> FieldListMap<'file_ref> {
|
|||
let key = tk::String::new(key_pin).to_string();
|
||||
let value_ref = property_pin.value();
|
||||
let value_pin = unsafe { Pin::new_unchecked(value_ref) };
|
||||
let value = tk::StringList::new(value_pin).to_vec();
|
||||
let value = tk::StringList::reference(value_pin).to_vec();
|
||||
(key, value)
|
||||
})
|
||||
.collect()
|
||||
|
|
Loading…
Reference in a new issue