musikr: implement main flow

This commit is contained in:
Alexander Capehart 2025-02-17 21:09:43 -07:00
parent de9a60d182
commit 8415db30ff
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
19 changed files with 294 additions and 174 deletions

View file

@ -1,10 +1,12 @@
use jni::{objects::{JByteArray, JClass, JMap, JObject, JString, JValueGen}, sys::jlong, JNIEnv};
use std::rc::Rc;
use std::cell::RefCell;
use crate::taglib::{
id3v1, id3v2, xiph, mp4, tk, audioproperties,
use jni::{
objects::{JObject, JValueGen},
sys::jlong,
JNIEnv,
};
use std::cell::RefCell;
use std::rc::Rc;
use crate::taglib::{audioproperties, id3v1, id3v2, mp4, xiph};
use crate::tagmap::JTagMap;
@ -56,7 +58,8 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
for mut frame in frames.to_vec() {
if let Some(text_frame) = frame.as_text_identification() {
if let Some(field_list) = text_frame.field_list() {
let values: Vec<String> = field_list.to_vec()
let values: Vec<String> = field_list
.to_vec()
.into_iter()
.map(|s| s.to_string())
.collect();
@ -110,7 +113,10 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
let covers = cover_list.to_vec();
// Prefer PNG/JPEG covers
let preferred_cover = covers.iter().find(|c| {
matches!(c.format(), mp4::CoverArtFormat::PNG | mp4::CoverArtFormat::JPEG)
matches!(
c.format(),
mp4::CoverArtFormat::PNG | mp4::CoverArtFormat::JPEG
)
});
if let Some(cover) = preferred_cover {
@ -125,7 +131,8 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
if let Some(data) = item.data() {
match data {
mp4::MP4Data::StringList(list) => {
let values: Vec<String> = list.to_vec().into_iter().map(|s| s.to_string()).collect();
let values: Vec<String> =
list.to_vec().into_iter().map(|s| s.to_string()).collect();
if key.starts_with("----") {
if let Some(split_idx) = key.find(':') {
let (atom_name, atom_desc) = key.split_at(split_idx);
@ -158,12 +165,18 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
pub fn build(&self) -> JObject {
// Create Properties object
let properties_class = self.env.borrow_mut().find_class("org/oxycblt/musikr/metadata/Properties").unwrap();
let properties_class = self
.env
.borrow_mut()
.find_class("org/oxycblt/musikr/metadata/Properties")
.unwrap();
let properties = if let Some(props) = &self.properties {
let mime_type = self.mime_type.as_deref().unwrap_or("").to_string();
let j_mime_type = self.env.borrow().new_string(mime_type).unwrap();
self.env.borrow_mut().new_object(
self.env
.borrow_mut()
.new_object(
properties_class,
"(Ljava/lang/String;JII)V",
&[
@ -172,27 +185,47 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
(props.bitrate() as i32).into(),
(props.sample_rate() as i32).into(),
],
).unwrap()
)
.unwrap()
} else {
let empty_mime = self.env.borrow().new_string("").unwrap();
self.env.borrow_mut().new_object(
self.env
.borrow_mut()
.new_object(
properties_class,
"(Ljava/lang/String;JII)V",
&[JValueGen::from(&empty_mime), 0i64.into(), 0i32.into(), 0i32.into()],
).unwrap()
&[
JValueGen::from(&empty_mime),
0i64.into(),
0i32.into(),
0i32.into(),
],
)
.unwrap()
};
// Create cover byte array if present
let cover_array = if let Some(cover_data) = &self.cover {
let array = self.env.borrow().new_byte_array(cover_data.len() as i32).unwrap();
self.env.borrow().set_byte_array_region(&array, 0, bytemuck::cast_slice(cover_data)).unwrap();
let array = self
.env
.borrow()
.new_byte_array(cover_data.len() as i32)
.unwrap();
self.env
.borrow()
.set_byte_array_region(&array, 0, bytemuck::cast_slice(cover_data))
.unwrap();
array.into()
} else {
JObject::null()
};
// Create Metadata object
let metadata_class = self.env.borrow_mut().find_class("org/oxycblt/musikr/metadata/Metadata").unwrap();
let metadata_class = self
.env
.borrow_mut()
.find_class("org/oxycblt/musikr/metadata/Metadata")
.unwrap();
self.env.borrow_mut().new_object(
metadata_class,
"(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;[BLorg/oxycblt/musikr/metadata/Properties;)V",

View file

@ -1,7 +1,7 @@
use crate::taglib::iostream::IOStream;
use crate::SharedEnv;
use jni::objects::{JObject, JValue};
use std::io::{Read, Seek, SeekFrom, Write};
use std::io::SeekFrom;
pub struct JInputStream<'local> {
env: SharedEnv<'local>,

View file

@ -1,36 +1,79 @@
use jni::objects::{JClass, JObject};
use jni::sys::jstring;
use jni::sys::jobject;
use jni::JNIEnv;
use std::cell::RefCell;
use std::rc::Rc;
mod jbuilder;
mod jstream;
mod taglib;
mod tagmap;
mod jbuilder;
use jbuilder::JMetadataBuilder;
use jstream::JInputStream;
use taglib::file_ref::FileRef;
use jbuilder::JMetadataBuilder;
type SharedEnv<'local> = Rc<RefCell<JNIEnv<'local>>>;
#[no_mangle]
pub extern "C" fn Java_org_oxycblt_musikr_metadata_MetadataJNI_openFile<'local>(
mut env: JNIEnv<'local>,
env: JNIEnv<'local>,
_class: JClass<'local>,
input: JObject<'local>,
) -> jstring {
) -> jobject {
// Create JInputStream from the Java input stream
let shared_env = Rc::new(RefCell::new(env));
let mut stream = JInputStream::new(shared_env.clone(), input);
let stream = JInputStream::new(shared_env.clone(), input);
let file_ref = FileRef::new(stream);
let file = file_ref.file();
let mut jbuilder = JMetadataBuilder::new(shared_env.clone());
match file {
Some(mut file) => {
if let Some(properties) = file.audio_properties() {
jbuilder.set_properties(properties);
}
if let Some(vorbis) = file.as_vorbis() {
jbuilder.set_mime_type("audio/ogg");
if let Some(tag) = vorbis.xiph_comments() {
jbuilder.set_xiph(&tag);
}
}
if let Some(opus) = file.as_opus() {
jbuilder.set_mime_type("audio/opus");
if let Some(tag) = opus.xiph_comments() {
jbuilder.set_xiph(&tag);
}
}
if let Some(mut flac) = file.as_flac() {
jbuilder.set_mime_type("audio/flac");
if let Some(tag) = flac.xiph_comments() {
jbuilder.set_xiph(&tag);
}
}
if let Some(mut mpeg) = file.as_mpeg() {
jbuilder.set_mime_type("audio/mpeg");
if let Some(tag) = mpeg.id3v1_tag() {
jbuilder.set_id3v1(&tag);
}
if let Some(tag) = mpeg.id3v2_tag() {
jbuilder.set_id3v2(&tag);
}
}
if let Some(mp4) = file.as_mp4() {
jbuilder.set_mime_type("audio/mp4");
if let Some(tag) = mp4.tag() {
jbuilder.set_mp4(&tag);
}
}
if let Some(mut wav) = file.as_wav() {
jbuilder.set_mime_type("audio/wav");
if let Some(tag) = wav.id3v2_tag() {
jbuilder.set_id3v2(&tag);
}
}
}
None => {}
}
// Return the title
let output = shared_env
.borrow_mut()
.new_string("title")
.expect("Couldn't create string!");
output.into_raw()
jbuilder.build().into_raw()
}

View file

@ -1,6 +1,5 @@
use super::bridge::CppAudioProperties;
use super::this::{RefThis, This};
use std::pin::Pin;
use super::this::RefThis;
pub struct AudioProperties<'file_ref> {
this: RefThis<'file_ref, CppAudioProperties>,

View file

@ -51,7 +51,9 @@ mod bridge_impl {
#[namespace = "TagLib"]
#[cxx_name = "IOStream"]
type CPPIOStream<'io_stream>;
fn wrap_RsIOStream<'io_stream>(stream: Box<DynIOStream<'io_stream>>) -> UniquePtr<CPPIOStream<'io_stream>>;
fn wrap_RsIOStream<'io_stream>(
stream: Box<DynIOStream<'io_stream>>,
) -> UniquePtr<CPPIOStream<'io_stream>>;
#[namespace = "TagLib"]
#[cxx_name = "FileRef"]
@ -258,9 +260,7 @@ mod bridge_impl {
#[cxx_name = "FrameList"]
type CPPID3v2FrameList;
#[namespace = "taglib_shim"]
fn FrameList_to_vector(
list: &CPPID3v2FrameList,
) -> UniquePtr<CxxVector<CPPFramePointer>>;
fn FrameList_to_vector(list: &CPPID3v2FrameList) -> UniquePtr<CxxVector<CPPFramePointer>>;
#[namespace = "taglib_shim"]
#[cxx_name = "FramePointer"]
@ -318,9 +318,7 @@ mod bridge_impl {
#[cxx_name = "StringList"]
type CPPStringList;
#[namespace = "taglib_shim"]
fn StringList_to_vector(
string_list: &CPPStringList,
) -> UniquePtr<CxxVector<CPPString>>;
fn StringList_to_vector(string_list: &CPPStringList) -> UniquePtr<CxxVector<CPPString>>;
#[namespace = "TagLib"]
#[cxx_name = "ByteVector"]
@ -332,7 +330,9 @@ mod bridge_impl {
#[cxx_name = "ByteVectorList"]
type CPPByteVectorList;
#[namespace = "taglib_shim"]
fn ByteVectorList_to_vector(list: &CPPByteVectorList) -> UniquePtr<CxxVector<CPPByteVector>>;
fn ByteVectorList_to_vector(
list: &CPPByteVectorList,
) -> UniquePtr<CxxVector<CPPByteVector>>;
}
}

View file

@ -1,16 +1,15 @@
use super::audioproperties::AudioProperties;
use super::bridge::{self, CPPFile, CPPMPEGFile};
use super::bridge::{self, CPPFile};
use super::flac::FLACFile;
use super::id3v2::ID3v2Tag;
use super::mp4::MP4File;
use super::mpeg::MPEGFile;
use super::ogg::OpusFile;
use super::ogg::VorbisFile;
use super::this::{RefThisMut, RefThis, This, ThisMut};
use std::pin::Pin;
use super::riff::WAVFile;
use super::this::{RefThis, RefThisMut};
pub struct File<'file_ref> {
this: RefThisMut<'file_ref, CPPFile>
this: RefThisMut<'file_ref, CPPFile>,
}
impl<'file_ref> File<'file_ref> {
@ -118,12 +117,16 @@ impl<'file_ref> File<'file_ref> {
}
pub fn as_mp4(&mut self) -> Option<MP4File<'file_ref>> {
let mp4_file = unsafe {
bridge::File_asMP4(self.this.ptr_mut())
};
let mp4_file = unsafe { bridge::File_asMP4(self.this.ptr_mut()) };
let mp4_ref = unsafe { mp4_file.as_mut() };
let mp4_this = mp4_ref.map(|mp4| RefThisMut::new(mp4));
mp4_this.map(|this| MP4File::new(this))
}
pub fn as_wav(&mut self) -> Option<WAVFile<'file_ref>> {
let wav_file = unsafe { bridge::File_asWAV(self.this.ptr_mut()) };
let wav_ref = unsafe { wav_file.as_mut() };
let wav_this = wav_ref.map(|wav| RefThisMut::new(wav));
wav_this.map(|this| WAVFile::new(this))
}
}

View file

@ -1,17 +1,16 @@
pub use super::bridge::CPPFLACFile;
pub use super::bridge::CPPFLACPicture;
use super::bridge::{CPPPictureList, FLACFile_pictureList, PictureList_to_vector, Picture_data, CPPByteVector};
use super::bridge::{
CPPPictureList, FLACFile_pictureList, PictureList_to_vector, Picture_data,
};
use super::id3v1::ID3v1Tag;
use super::id3v2::ID3v2Tag;
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut};
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: RefThisMut<'file_ref, CPPFLACFile>
this: RefThisMut<'file_ref, CPPFLACFile>,
}
impl<'file_ref> FLACFile<'file_ref> {
@ -19,7 +18,6 @@ impl<'file_ref> FLACFile<'file_ref> {
Self { this }
}
pub fn xiph_comments(&mut self) -> Option<XiphComment<'file_ref>> {
let tag = self.this.pin_mut().xiphComment(false);
let tag_ref = unsafe {

View file

@ -1,6 +1,6 @@
use super::bridge::{self, CPPID3v1Tag};
use super::this::{RefThisMut, RefThis, This, OwnedThis};
use super::tk::{String, OwnedString};
use super::this::{OwnedThis, RefThisMut};
use super::tk::{OwnedString, String};
pub struct ID3v1Tag<'file_ref> {
this: RefThisMut<'file_ref, CPPID3v1Tag>,

View file

@ -1,9 +1,9 @@
use super::bridge::{
self, CPPID3v2AttachedPictureFrame, CPPID3v2Frame, CPPID3v2FrameList, CPPID3v2Tag,
CPPID3v2TextIdentificationFrame, CPPID3v2UserTextIdentificationFrame, CPPStringList, CPPByteVector,
self, CPPID3v2AttachedPictureFrame, CPPID3v2Frame, CPPID3v2FrameList,
CPPID3v2Tag, CPPID3v2TextIdentificationFrame, CPPID3v2UserTextIdentificationFrame,
};
use super::tk::{self, ByteVector, StringList, OwnedByteVector, OwnedStringList};
use super::this::{OwnedThis, RefThisMut, RefThis, This};
use super::this::{OwnedThis, RefThis, RefThisMut};
use super::tk::{self, ByteVector, OwnedByteVector, OwnedStringList, StringList};
pub struct ID3v2Tag<'file_ref> {
this: RefThisMut<'file_ref, CPPID3v2Tag>,

View file

@ -1,7 +1,6 @@
use super::bridge::{self, CPPIOStream};
use cxx::UniquePtr;
use std::io::{Read, Seek, SeekFrom, Write};
use std::pin::Pin;
use std::io::{Seek, SeekFrom};
pub trait IOStream {
fn read_block(&mut self, buffer: &mut [u8]) -> usize;
@ -22,9 +21,7 @@ impl<'io_stream> BridgedIOStream<'io_stream> {
pub fn new<T: IOStream + 'io_stream>(stream: T) -> Self {
let rs_stream: Box<DynIOStream<'io_stream>> = Box::new(DynIOStream(Box::new(stream)));
let cpp_stream: UniquePtr<CPPIOStream<'io_stream>> = bridge::wrap_RsIOStream(rs_stream);
BridgedIOStream {
cpp_stream,
}
BridgedIOStream { cpp_stream }
}
pub fn cpp_stream(&self) -> &UniquePtr<CPPIOStream> {

View file

@ -1,15 +1,15 @@
mod bridge;
mod this;
pub mod iostream;
pub mod file_ref;
pub mod file;
pub mod audioproperties;
pub mod ogg;
pub mod mpeg;
mod bridge;
pub mod file;
pub mod file_ref;
pub mod flac;
pub mod xiph;
pub mod tk;
pub mod id3v2;
pub mod id3v1;
pub mod id3v2;
pub mod iostream;
pub mod mp4;
pub mod mpeg;
pub mod ogg;
pub mod riff;
mod this;
pub mod tk;
pub mod xiph;

View file

@ -1,9 +1,11 @@
pub use super::bridge::CPPMP4Tag;
use super::bridge::{CPPFile, CPPIntPair, CPPItemMap, CPPItemMapEntry, CPPMP4File, CPPMP4Item, ItemMap_to_entries, MP4ItemType};
use super::bridge::{
CPPIntPair, CPPItemMap, CPPMP4File, CPPMP4Item, ItemMap_to_entries,
MP4ItemType,
};
use super::this::{OwnedThis, RefThis, RefThisMut};
use super::tk;
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut, This};
use std::collections::HashMap;
use std::pin::Pin;
pub struct MP4File<'file_ref> {
this: RefThisMut<'file_ref, CPPMP4File>,
@ -53,8 +55,8 @@ impl<'file_ref> ItemMap<'file_ref> {
pub fn to_hashmap(&self) -> HashMap<String, MP4Item<'file_ref>> {
let cxx_vec = ItemMap_to_entries(self.this.as_ref());
let vec: Vec<(String, MP4Item<'file_ref>)> =
cxx_vec.iter()
let vec: Vec<(String, MP4Item<'file_ref>)> = cxx_vec
.iter()
.map(|property| {
// SAFETY:
// - This pin is only used in this unsafe scope.
@ -101,24 +103,30 @@ impl<'file_ref> MP4Item<'file_ref> {
let pair = super::bridge::Item_toIntPair(self.this.as_ref());
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::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 = 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 = OwnedThis::new(byte_vector_list).unwrap();
Some(MP4Data::ByteVectorList(tk::ByteVectorList::new(byte_vector_list_this)))
},
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 = OwnedThis::new(cover_art_list).unwrap();
Some(MP4Data::CoverArtList(CoverArtList::new(cover_art_list_this)))
Some(MP4Data::CoverArtList(CoverArtList::new(
cover_art_list_this,
)))
}
})
}

View file

@ -1,8 +1,7 @@
use super::bridge::{self, CPPMPEGFile};
use super::bridge::{CPPMPEGFile};
use super::id3v1::ID3v1Tag;
use super::id3v2::ID3v2Tag;
use super::this::{RefThisMut, This, ThisMut};
use std::pin::Pin;
use super::this::{RefThisMut, ThisMut};
pub struct MPEGFile<'file_ref> {
this: RefThisMut<'file_ref, CPPMPEGFile>,

View file

@ -1,7 +1,6 @@
pub use super::bridge::{CPPOpusFile, CPPVorbisFile};
use super::this::RefThisMut;
use super::xiph::XiphComment;
use super::this::{RefThisMut, RefThis, This};
use std::pin::Pin;
pub struct VorbisFile<'file_ref> {
this: RefThisMut<'file_ref, CPPVorbisFile>,

View file

@ -1,7 +1,6 @@
use super::bridge::{self, CPPWAVFile};
use super::bridge::{CPPWAVFile};
use super::id3v2::ID3v2Tag;
use super::this::{RefThisMut, This, ThisMut};
use std::pin::Pin;
use super::this::RefThisMut;
pub struct WAVFile<'file_ref> {
this: RefThisMut<'file_ref, CPPWAVFile>,

View file

@ -1,7 +1,7 @@
use super::bridge::{TagLibAllocated, TagLibRef, TagLibShared};
use cxx::{memory::UniquePtrTarget, UniquePtr};
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.
///
@ -10,7 +10,7 @@ use super::bridge::{TagLibAllocated, TagLibRef, TagLibShared};
/// 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: TagLibAllocated> : AsRef<T> {}
pub trait This<'file_ref, T: TagLibAllocated>: AsRef<T> {}
/// A taglib-FFI-specific trait representing a C++ object returned by the library.
///
@ -22,13 +22,13 @@ pub trait This<'file_ref, T: TagLibAllocated> : 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: TagLibAllocated> : 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: TagLibRef> {
this: &'file_ref T
this: &'file_ref T,
}
impl<'file_ref, T: TagLibRef> RefThis<'file_ref, T> {
@ -155,9 +155,10 @@ impl<'file_ref, T: TagLibShared + UniquePtrTarget> AsRef<T> for OwnedThis<'file_
impl<'file_ref, T: TagLibShared + UniquePtrTarget> This<'file_ref, T> for OwnedThis<'file_ref, T> {}
impl<'file_ref, T: TagLibShared + 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

@ -1,14 +1,12 @@
use super::bridge;
use super::this::{RefThis, RefThisMut, This, OwnedThis};
use cxx::{memory::UniquePtrTarget, UniquePtr};
use super::this::{OwnedThis, RefThis, RefThisMut, This};
use std::marker::PhantomData;
use std::pin::Pin;
use std::{ffi::CStr, string::ToString};
pub use bridge::CPPString as InnerString;
pub use bridge::CPPStringList as InnerStringList;
pub use bridge::CPPByteVector as InnerByteVector;
pub use bridge::CPPByteVectorList as InnerByteVectorList;
pub use bridge::CPPString as InnerString;
pub use bridge::CPPStringList as InnerStringList;
pub struct String<'file_ref, T: This<'file_ref, InnerString>> {
_data: PhantomData<&'file_ref ()>,
@ -17,7 +15,10 @@ pub struct String<'file_ref, T: This<'file_ref, InnerString>> {
impl<'file_ref, T: This<'file_ref, InnerString>> String<'file_ref, T> {
pub(super) fn new(this: T) -> Self {
Self { _data: PhantomData, this }
Self {
_data: PhantomData,
this,
}
}
}
@ -49,13 +50,12 @@ pub struct StringList<'file_ref, T: This<'file_ref, InnerStringList>> {
this: T,
}
pub type OwnedStringList<'file_ref> = StringList<'file_ref, OwnedThis<'file_ref, InnerStringList>>;
pub type RefStringList<'file_ref> = StringList<'file_ref, RefThis<'file_ref, InnerStringList>>;
pub type RefStringListMut<'file_ref> = StringList<'file_ref, RefThisMut<'file_ref, InnerStringList>>;
impl<'file_ref, T: This<'file_ref, InnerStringList>> StringList<'file_ref, T> {
pub(super) fn new(this: T) -> Self {
Self { _data: PhantomData, this }
Self {
_data: PhantomData,
this,
}
}
pub fn to_vec(&self) -> Vec<std::string::String> {
@ -70,6 +70,11 @@ impl<'file_ref, T: This<'file_ref, InnerStringList>> StringList<'file_ref, T> {
}
}
pub type OwnedStringList<'file_ref> = StringList<'file_ref, OwnedThis<'file_ref, InnerStringList>>;
pub type RefStringList<'file_ref> = StringList<'file_ref, RefThis<'file_ref, InnerStringList>>;
pub type RefStringListMut<'file_ref> =
StringList<'file_ref, RefThisMut<'file_ref, InnerStringList>>;
pub struct ByteVector<'file_ref, T: This<'file_ref, InnerByteVector>> {
_data: PhantomData<&'file_ref InnerByteVector>,
this: T,
@ -77,7 +82,10 @@ pub struct ByteVector<'file_ref, T: This<'file_ref, InnerByteVector>> {
impl<'file_ref, T: This<'file_ref, InnerByteVector>> ByteVector<'file_ref, T> {
pub(super) fn new(this: T) -> Self {
Self { _data: PhantomData, this }
Self {
_data: PhantomData,
this,
}
}
pub fn to_vec(&self) -> Vec<u8> {
@ -107,7 +115,8 @@ impl<'file_ref, T: This<'file_ref, InnerByteVector>> ByteVector<'file_ref, T> {
pub type OwnedByteVector<'file_ref> = ByteVector<'file_ref, OwnedThis<'file_ref, InnerByteVector>>;
pub type RefByteVector<'file_ref> = ByteVector<'file_ref, RefThis<'file_ref, InnerByteVector>>;
pub type RefByteVectorMut<'file_ref> = ByteVector<'file_ref, RefThisMut<'file_ref, InnerByteVector>>;
pub type RefByteVectorMut<'file_ref> =
ByteVector<'file_ref, RefThisMut<'file_ref, InnerByteVector>>;
pub struct ByteVectorList<'file_ref, T: This<'file_ref, InnerByteVectorList>> {
_data: PhantomData<&'file_ref InnerByteVectorList>,
@ -116,7 +125,10 @@ pub struct ByteVectorList<'file_ref, T: This<'file_ref, InnerByteVectorList>> {
impl<'file_ref, T: This<'file_ref, InnerByteVectorList>> ByteVectorList<'file_ref, T> {
pub(super) fn new(this: T) -> Self {
Self { _data: PhantomData, this }
Self {
_data: PhantomData,
this,
}
}
pub fn to_vec(&self) -> Vec<Vec<u8>> {
@ -128,7 +140,9 @@ impl<'file_ref, T: This<'file_ref, InnerByteVectorList>> ByteVectorList<'file_re
}
}
pub type OwnedByteVectorList<'file_ref> = ByteVectorList<'file_ref, OwnedThis<'file_ref, InnerByteVectorList>>;
pub type RefByteVectorList<'file_ref> = ByteVectorList<'file_ref, RefThis<'file_ref, InnerByteVectorList>>;
pub type RefByteVectorListMut<'file_ref> = ByteVectorList<'file_ref, RefThisMut<'file_ref, InnerByteVectorList>>;
pub type OwnedByteVectorList<'file_ref> =
ByteVectorList<'file_ref, OwnedThis<'file_ref, InnerByteVectorList>>;
pub type RefByteVectorList<'file_ref> =
ByteVectorList<'file_ref, RefThis<'file_ref, InnerByteVectorList>>;
pub type RefByteVectorListMut<'file_ref> =
ByteVectorList<'file_ref, RefThisMut<'file_ref, InnerByteVectorList>>;

View file

@ -1,10 +1,9 @@
pub use super::bridge::CPPXiphComment;
use super::bridge::{CPPFieldListMap, FieldListMap_to_entries, XiphComment_pictureList};
pub use super::flac::PictureList;
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut};
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: RefThisMut<'file_ref, CPPXiphComment>,

View file

@ -1,7 +1,10 @@
use jni::{
objects::{JObject, JValueGen},
JNIEnv,
};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use jni::{objects::{JObject, JValueGen}, JNIEnv};
pub struct JTagMap<'local> {
env: Rc<RefCell<JNIEnv<'local>>>,
@ -27,7 +30,12 @@ impl<'local> JTagMap<'local> {
self.map.entry(id).or_default().extend(values);
}
pub fn add_combined(&mut self, id: impl Into<String>, description: impl Into<String>, value: impl Into<String>) {
pub fn add_combined(
&mut self,
id: impl Into<String>,
description: impl Into<String>,
value: impl Into<String>,
) {
let id = id.into();
let description = description.into();
let value = value.into();
@ -36,8 +44,16 @@ impl<'local> JTagMap<'local> {
}
pub fn get_object(&self) -> JObject {
let map_class = self.env.borrow_mut().find_class("java/util/HashMap").unwrap();
let map = self.env.borrow_mut().new_object(&map_class, "()V", &[]).unwrap();
let map_class = self
.env
.borrow_mut()
.find_class("java/util/HashMap")
.unwrap();
let map = self
.env
.borrow_mut()
.new_object(&map_class, "()V", &[])
.unwrap();
for (key, values) in &self.map {
let j_key = self.env.borrow().new_string(key).unwrap();
@ -47,26 +63,38 @@ impl<'local> JTagMap<'local> {
.collect();
// Create ArrayList for values
let array_list_class = self.env.borrow_mut().find_class("java/util/ArrayList").unwrap();
let array_list = self.env.borrow_mut().new_object(array_list_class, "()V", &[]).unwrap();
let array_list_class = self
.env
.borrow_mut()
.find_class("java/util/ArrayList")
.unwrap();
let array_list = self
.env
.borrow_mut()
.new_object(array_list_class, "()V", &[])
.unwrap();
for value in j_values {
self.env.borrow_mut()
self.env
.borrow_mut()
.call_method(
&array_list,
"add",
"(Ljava/lang/Object;)Z",
&[JValueGen::from(&value)]
).unwrap();
&[JValueGen::from(&value)],
)
.unwrap();
}
self.env.borrow_mut()
self.env
.borrow_mut()
.call_method(
&map,
"put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
&[JValueGen::from(&j_key), JValueGen::from(&array_list)]
).unwrap();
&[JValueGen::from(&j_key), JValueGen::from(&array_list)],
)
.unwrap();
}
map