musikr: minimize ffi shims
This commit is contained in:
parent
cf597cb98e
commit
acee4ddedd
9 changed files with 69 additions and 228 deletions
|
@ -110,8 +110,6 @@ fn main() {
|
|||
cxx_build::bridge("src/taglib/ffi.rs")
|
||||
.file("shim/iostream_shim.cpp")
|
||||
.file("shim/file_shim.cpp")
|
||||
.file("shim/string_shim.cpp")
|
||||
.file("shim/audioproperties_shim.cpp")
|
||||
.include(format!("taglib/pkg/{}/include", arch))
|
||||
.include("shim")
|
||||
.include(".") // Add the current directory to include path
|
||||
|
@ -124,9 +122,5 @@ fn main() {
|
|||
println!("cargo:rerun-if-changed=shim/iostream_shim.cpp");
|
||||
println!("cargo:rerun-if-changed=shim/file_shim.hpp");
|
||||
println!("cargo:rerun-if-changed=shim/file_shim.cpp");
|
||||
println!("cargo:rerun-if-changed=shim/string_shim.hpp");
|
||||
println!("cargo:rerun-if-changed=shim/string_shim.cpp");
|
||||
println!("cargo:rerun-if-changed=shim/audioproperties_shim.hpp");
|
||||
println!("cargo:rerun-if-changed=shim/audioproperties_shim.cpp");
|
||||
println!("cargo:rerun-if-changed=src/taglib/ffi.rs");
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
#include "audioproperties_shim.hpp"
|
||||
#include <taglib/tfile.h>
|
||||
|
||||
namespace taglib_shim {
|
||||
|
||||
const TagLib::AudioProperties* File_audioProperties(const TagLib::File& file) {
|
||||
return file.audioProperties();
|
||||
}
|
||||
|
||||
int AudioProperties_lengthInMilliseconds(const TagLib::AudioProperties* properties) {
|
||||
return properties->lengthInMilliseconds();
|
||||
}
|
||||
|
||||
int AudioProperties_bitrateInKilobitsPerSecond(const TagLib::AudioProperties* properties) {
|
||||
return properties->bitrate();
|
||||
}
|
||||
|
||||
int AudioProperties_sampleRateInHz(const TagLib::AudioProperties* properties) {
|
||||
return properties->sampleRate();
|
||||
}
|
||||
|
||||
int AudioProperties_numberOfChannels(const TagLib::AudioProperties* properties) {
|
||||
return properties->channels();
|
||||
}
|
||||
|
||||
} // namespace taglib_shim
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <taglib/audioproperties.h>
|
||||
#include <taglib/tfile.h>
|
||||
|
||||
namespace taglib_shim {
|
||||
|
||||
// Audio Properties methods
|
||||
const TagLib::AudioProperties* File_audioProperties(const TagLib::File& file);
|
||||
int AudioProperties_lengthInMilliseconds(const TagLib::AudioProperties* properties);
|
||||
int AudioProperties_bitrateInKilobitsPerSecond(const TagLib::AudioProperties* properties);
|
||||
int AudioProperties_sampleRateInHz(const TagLib::AudioProperties* properties);
|
||||
int AudioProperties_numberOfChannels(const TagLib::AudioProperties* properties);
|
||||
|
||||
} // namespace taglib_shim
|
|
@ -2,65 +2,37 @@
|
|||
|
||||
namespace taglib_shim {
|
||||
|
||||
// FileRef helper functions
|
||||
bool FileRef_isNull(const TagLib::FileRef& ref) {
|
||||
return ref.isNull();
|
||||
}
|
||||
|
||||
const TagLib::File& FileRef_file(const TagLib::FileRef& ref) {
|
||||
return *ref.file();
|
||||
}
|
||||
|
||||
// File tag methods
|
||||
bool File_tag(const TagLib::File& file) {
|
||||
return file.tag() != nullptr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Keep the empty string as a static member to ensure it lives long enough
|
||||
const TagLib::String empty_string;
|
||||
}
|
||||
|
||||
const TagLib::String& File_tag_title(const TagLib::File& file) {
|
||||
if (auto* tag = file.tag()) {
|
||||
static TagLib::String title;
|
||||
title = tag->title();
|
||||
return title;
|
||||
}
|
||||
return empty_string;
|
||||
}
|
||||
|
||||
// File type checking functions
|
||||
bool File_isMPEG(const TagLib::File& file) {
|
||||
return dynamic_cast<const TagLib::MPEG::File*>(&file) != nullptr;
|
||||
bool File_isMPEG(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::MPEG::File*>(file) != nullptr;
|
||||
}
|
||||
|
||||
bool File_isFLAC(const TagLib::File& file) {
|
||||
return dynamic_cast<const TagLib::FLAC::File*>(&file) != nullptr;
|
||||
bool File_isFLAC(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::FLAC::File*>(file) != nullptr;
|
||||
}
|
||||
|
||||
bool File_isMP4(const TagLib::File& file) {
|
||||
return dynamic_cast<const TagLib::MP4::File*>(&file) != nullptr;
|
||||
bool File_isMP4(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::MP4::File*>(file) != nullptr;
|
||||
}
|
||||
|
||||
bool File_isOgg(const TagLib::File& file) {
|
||||
return dynamic_cast<const TagLib::Ogg::File*>(&file) != nullptr;
|
||||
bool File_isOgg(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::Ogg::File*>(file) != nullptr;
|
||||
}
|
||||
|
||||
bool File_isOpus(const TagLib::File& file) {
|
||||
return dynamic_cast<const TagLib::Ogg::Opus::File*>(&file) != nullptr;
|
||||
bool File_isOpus(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::Ogg::Opus::File*>(file) != nullptr;
|
||||
}
|
||||
|
||||
bool File_isWAV(const TagLib::File& file) {
|
||||
return dynamic_cast<const TagLib::RIFF::WAV::File*>(&file) != nullptr;
|
||||
bool File_isWAV(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::RIFF::WAV::File*>(file) != nullptr;
|
||||
}
|
||||
|
||||
bool File_isWavPack(const TagLib::File& file) {
|
||||
return dynamic_cast<const TagLib::WavPack::File*>(&file) != nullptr;
|
||||
bool File_isWavPack(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::WavPack::File*>(file) != nullptr;
|
||||
}
|
||||
|
||||
bool File_isAPE(const TagLib::File& file) {
|
||||
return dynamic_cast<const TagLib::APE::File*>(&file) != nullptr;
|
||||
bool File_isAPE(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::APE::File*>(file) != nullptr;
|
||||
}
|
||||
|
||||
} // namespace taglib_shim
|
|
@ -15,29 +15,15 @@
|
|||
|
||||
namespace taglib_shim {
|
||||
|
||||
// FileRef helper functions
|
||||
bool FileRef_isNull(const TagLib::FileRef& ref);
|
||||
const TagLib::File& FileRef_file(const TagLib::FileRef& ref);
|
||||
|
||||
// File tag methods
|
||||
bool File_tag(const TagLib::File& file);
|
||||
const TagLib::String& File_tag_title(const TagLib::File& file);
|
||||
|
||||
// File type checking functions
|
||||
bool File_isMPEG(const TagLib::File& file);
|
||||
bool File_isFLAC(const TagLib::File& file);
|
||||
bool File_isMP4(const TagLib::File& file);
|
||||
bool File_isOgg(const TagLib::File& file);
|
||||
bool File_isOpus(const TagLib::File& file);
|
||||
bool File_isWAV(const TagLib::File& file);
|
||||
bool File_isWavPack(const TagLib::File& file);
|
||||
bool File_isAPE(const TagLib::File& file);
|
||||
bool File_isMPEG(TagLib::File* file);
|
||||
bool File_isFLAC(TagLib::File* file);
|
||||
bool File_isMP4(TagLib::File* file);
|
||||
bool File_isOgg(TagLib::File* file);
|
||||
bool File_isOpus(TagLib::File* file);
|
||||
bool File_isWAV(TagLib::File* file);
|
||||
bool File_isWavPack(TagLib::File* file);
|
||||
bool File_isAPE(TagLib::File* file);
|
||||
|
||||
// Audio Properties methods
|
||||
const TagLib::AudioProperties* File_audioProperties(const TagLib::File& file);
|
||||
int AudioProperties_length(const TagLib::AudioProperties* properties);
|
||||
int AudioProperties_bitrate(const TagLib::AudioProperties* properties);
|
||||
int AudioProperties_sampleRate(const TagLib::AudioProperties* properties);
|
||||
int AudioProperties_channels(const TagLib::AudioProperties* properties);
|
||||
|
||||
} // namespace taglib_shim
|
|
@ -1,13 +0,0 @@
|
|||
#include "string_shim.hpp"
|
||||
|
||||
namespace taglib_shim {
|
||||
|
||||
const char* to_string(const TagLib::String& str) {
|
||||
return str.toCString(true);
|
||||
}
|
||||
|
||||
bool isEmpty(const TagLib::String& str) {
|
||||
return str.isEmpty();
|
||||
}
|
||||
|
||||
} // namespace taglib_shim
|
|
@ -1,11 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <taglib/tstring.h>
|
||||
|
||||
namespace taglib_shim {
|
||||
|
||||
// String utilities
|
||||
const char* to_string(const TagLib::String& str);
|
||||
bool isEmpty(const TagLib::String& str);
|
||||
|
||||
} // namespace taglib_shim
|
|
@ -5,8 +5,6 @@ pub(crate) mod bindings {
|
|||
include!("taglib/tstring.h");
|
||||
include!("shim/iostream_shim.hpp");
|
||||
include!("shim/file_shim.hpp");
|
||||
include!("shim/string_shim.hpp");
|
||||
include!("shim/audioproperties_shim.hpp");
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
type FileRef;
|
||||
|
@ -30,49 +28,39 @@ pub(crate) mod bindings {
|
|||
fn new_FileRef_from_stream(stream: UniquePtr<RustIOStream>) -> UniquePtr<FileRef>;
|
||||
|
||||
// FileRef helper functions
|
||||
#[namespace = "taglib_shim"]
|
||||
fn FileRef_isNull(ref_: &FileRef) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn FileRef_file(ref_: &FileRef) -> &File;
|
||||
fn isNull(self: Pin<&FileRef>) -> bool;
|
||||
fn file(self: Pin<&FileRef>) -> *mut File;
|
||||
|
||||
// File tag methods
|
||||
#[namespace = "taglib_shim"]
|
||||
fn File_tag_title(file: &File) -> &TagString;
|
||||
fn audioProperties(self: Pin<&File>) -> *mut AudioProperties;
|
||||
|
||||
// File type checking functions
|
||||
#[namespace = "taglib_shim"]
|
||||
fn File_isMPEG(file: &File) -> bool;
|
||||
unsafe fn File_isMPEG(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn File_isFLAC(file: &File) -> bool;
|
||||
unsafe fn File_isFLAC(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn File_isMP4(file: &File) -> bool;
|
||||
unsafe fn File_isMP4(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn File_isOgg(file: &File) -> bool;
|
||||
unsafe fn File_isOgg(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn File_isOpus(file: &File) -> bool;
|
||||
unsafe fn File_isOpus(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn File_isWAV(file: &File) -> bool;
|
||||
unsafe fn File_isWAV(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn File_isWavPack(file: &File) -> bool;
|
||||
unsafe fn File_isWavPack(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn File_isAPE(file: &File) -> bool;
|
||||
unsafe fn File_isAPE(file: *mut File) -> bool;
|
||||
|
||||
// Audio Properties methods
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_audioProperties(file: &File) -> *const AudioProperties;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn AudioProperties_lengthInMilliseconds(properties: *const AudioProperties) -> i32;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn AudioProperties_bitrateInKilobitsPerSecond(properties: *const AudioProperties) -> i32;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn AudioProperties_sampleRateInHz(properties: *const AudioProperties) -> i32;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn AudioProperties_numberOfChannels(properties: *const AudioProperties) -> i32;
|
||||
// AudioProperties methods
|
||||
fn lengthInMilliseconds(self: Pin<&AudioProperties>) -> i32;
|
||||
fn bitrate(self: Pin<&AudioProperties>) -> i32;
|
||||
fn sampleRate(self: Pin<&AudioProperties>) -> i32;
|
||||
fn channels(self: Pin<&AudioProperties>) -> i32;
|
||||
|
||||
// String conversion utilities
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn to_string(s: &TagString) -> *const c_char;
|
||||
unsafe fn toCString(self: Pin<&TagString>, unicode: bool) -> *const c_char;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn isEmpty(s: &TagString) -> bool;
|
||||
fn isEmpty(self: Pin<&TagString>) -> bool;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
mod ffi;
|
||||
mod stream;
|
||||
|
||||
use std::pin::{pin, Pin};
|
||||
|
||||
use cxx::UniquePtr;
|
||||
pub use stream::{RustStream, TagLibStream};
|
||||
use ffi::bindings;
|
||||
|
||||
|
@ -15,39 +18,30 @@ pub struct AudioProperties {
|
|||
|
||||
pub enum File {
|
||||
Unknown {
|
||||
title: Option<String>,
|
||||
audio_properties: Option<AudioProperties>,
|
||||
},
|
||||
MP3 {
|
||||
title: Option<String>,
|
||||
audio_properties: Option<AudioProperties>,
|
||||
},
|
||||
FLAC {
|
||||
title: Option<String>,
|
||||
audio_properties: Option<AudioProperties>,
|
||||
},
|
||||
MP4 {
|
||||
title: Option<String>,
|
||||
audio_properties: Option<AudioProperties>,
|
||||
},
|
||||
OGG {
|
||||
title: Option<String>,
|
||||
audio_properties: Option<AudioProperties>,
|
||||
},
|
||||
Opus {
|
||||
title: Option<String>,
|
||||
audio_properties: Option<AudioProperties>,
|
||||
},
|
||||
WAV {
|
||||
title: Option<String>,
|
||||
audio_properties: Option<AudioProperties>,
|
||||
},
|
||||
WavPack {
|
||||
title: Option<String>,
|
||||
audio_properties: Option<AudioProperties>,
|
||||
},
|
||||
APE {
|
||||
title: Option<String>,
|
||||
audio_properties: Option<AudioProperties>,
|
||||
},
|
||||
}
|
||||
|
@ -55,28 +49,12 @@ pub enum File {
|
|||
impl Default for File {
|
||||
fn default() -> Self {
|
||||
File::Unknown {
|
||||
title: None,
|
||||
audio_properties: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
/// Get the title of the file, if available
|
||||
pub fn title(&self) -> Option<&str> {
|
||||
match self {
|
||||
File::Unknown { title, .. } |
|
||||
File::MP3 { title, .. } |
|
||||
File::FLAC { title, .. } |
|
||||
File::MP4 { title, .. } |
|
||||
File::OGG { title, .. } |
|
||||
File::Opus { title, .. } |
|
||||
File::WAV { title, .. } |
|
||||
File::WavPack { title, .. } |
|
||||
File::APE { title, .. } => title.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the audio properties of the file, if available
|
||||
pub fn audio_properties(&self) -> Option<&AudioProperties> {
|
||||
match self {
|
||||
|
@ -111,38 +89,26 @@ impl FileRef {
|
|||
let iostream = unsafe { ffi::bindings::new_rust_iostream(raw_stream) };
|
||||
|
||||
// Create FileRef from iostream
|
||||
let inner = ffi::bindings::new_FileRef_from_stream(iostream);
|
||||
if ffi::bindings::FileRef_isNull(&inner) {
|
||||
let file_ref = ffi::bindings::new_FileRef_from_stream(iostream);
|
||||
if file_ref.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Extract data from C++ objects
|
||||
let file_ref = &inner;
|
||||
let file_ptr = ffi::bindings::FileRef_file(&file_ref);
|
||||
|
||||
// Extract title
|
||||
let title = {
|
||||
let title = ffi::bindings::File_tag_title(file_ptr);
|
||||
if ffi::bindings::isEmpty(title) {
|
||||
None
|
||||
} else {
|
||||
let cstr = unsafe { ffi::bindings::to_string(title) };
|
||||
unsafe { std::ffi::CStr::from_ptr(cstr) }
|
||||
.to_str()
|
||||
.ok()
|
||||
.map(|s| s.to_owned())
|
||||
}
|
||||
};
|
||||
let pinned_file_ref = unsafe { Pin::new_unchecked(file_ref.as_ref().unwrap()) };
|
||||
let file_ptr = pinned_file_ref.file();
|
||||
|
||||
// Extract audio properties
|
||||
let audio_properties = unsafe {
|
||||
let props_ptr = ffi::bindings::File_audioProperties(file_ptr);
|
||||
let audio_properties = {
|
||||
let pinned_file = unsafe { Pin::new_unchecked(&*file_ptr) };
|
||||
let props_ptr = pinned_file.audioProperties();
|
||||
if !props_ptr.is_null() {
|
||||
let props = unsafe { Pin::new_unchecked(&*props_ptr) };
|
||||
Some(AudioProperties {
|
||||
length_in_milliseconds: ffi::bindings::AudioProperties_lengthInMilliseconds(props_ptr),
|
||||
bitrate_in_kilobits_per_second: ffi::bindings::AudioProperties_bitrateInKilobitsPerSecond(props_ptr),
|
||||
sample_rate_in_hz: ffi::bindings::AudioProperties_sampleRateInHz(props_ptr),
|
||||
number_of_channels: ffi::bindings::AudioProperties_numberOfChannels(props_ptr),
|
||||
length_in_milliseconds: props.lengthInMilliseconds(),
|
||||
bitrate_in_kilobits_per_second: props.bitrate(),
|
||||
sample_rate_in_hz: props.sampleRate(),
|
||||
number_of_channels: props.channels(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -150,30 +116,30 @@ impl FileRef {
|
|||
};
|
||||
|
||||
// Determine file type and create appropriate variant
|
||||
let file = {
|
||||
let file = unsafe {
|
||||
if ffi::bindings::File_isMPEG(file_ptr) {
|
||||
File::MP3 { title, audio_properties }
|
||||
File::MP3 { audio_properties }
|
||||
} else if ffi::bindings::File_isFLAC(file_ptr) {
|
||||
File::FLAC { title, audio_properties }
|
||||
File::FLAC { audio_properties }
|
||||
} else if ffi::bindings::File_isMP4(file_ptr) {
|
||||
File::MP4 { title, audio_properties }
|
||||
File::MP4 { audio_properties }
|
||||
} else if ffi::bindings::File_isOpus(file_ptr) {
|
||||
File::Opus { title, audio_properties }
|
||||
File::Opus { audio_properties }
|
||||
} else if ffi::bindings::File_isOgg(file_ptr) {
|
||||
File::OGG { title, audio_properties }
|
||||
File::OGG { audio_properties }
|
||||
} else if ffi::bindings::File_isWAV(file_ptr) {
|
||||
File::WAV { title, audio_properties }
|
||||
File::WAV { audio_properties }
|
||||
} else if ffi::bindings::File_isWavPack(file_ptr) {
|
||||
File::WavPack { title, audio_properties }
|
||||
File::WavPack { audio_properties }
|
||||
} else if ffi::bindings::File_isAPE(file_ptr) {
|
||||
File::APE { title, audio_properties }
|
||||
File::APE { audio_properties }
|
||||
} else {
|
||||
File::Unknown { title, audio_properties }
|
||||
File::Unknown { audio_properties }
|
||||
}
|
||||
};
|
||||
|
||||
// Clean up C++ objects - they will be dropped when inner is dropped
|
||||
drop(inner);
|
||||
// Clean up C++ objects - they will be dropped when file_ref is dropped
|
||||
drop(file_ref);
|
||||
|
||||
Some(FileRef { file })
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue