Skip to content

Commit 359e80d

Browse files
authored
Merge pull request #813 from RealKC/utf8-apis
glib: Bind more `g_utf8` APIs
2 parents a452bdf + bd37eff commit 359e80d

File tree

5 files changed

+148
-1
lines changed

5 files changed

+148
-1
lines changed

glib/Gir.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ generate = [
2424
"GLib.LogWriterOutput",
2525
"GLib.MainContextFlags",
2626
"GLib.MarkupError",
27+
"GLib.NormalizeMode",
2728
"GLib.OptionArg",
2829
"GLib.OptionFlags",
2930
"GLib.SeekType",

glib/src/auto/enums.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,66 @@ impl ErrorDomain for MarkupError {
805805
}
806806
}
807807

808+
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
809+
#[non_exhaustive]
810+
#[doc(alias = "GNormalizeMode")]
811+
pub enum NormalizeMode {
812+
#[doc(alias = "G_NORMALIZE_DEFAULT")]
813+
Default,
814+
#[doc(alias = "G_NORMALIZE_DEFAULT_COMPOSE")]
815+
DefaultCompose,
816+
#[doc(alias = "G_NORMALIZE_ALL")]
817+
All,
818+
#[doc(alias = "G_NORMALIZE_ALL_COMPOSE")]
819+
AllCompose,
820+
#[doc(hidden)]
821+
__Unknown(i32),
822+
}
823+
824+
impl fmt::Display for NormalizeMode {
825+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
826+
write!(
827+
f,
828+
"NormalizeMode::{}",
829+
match *self {
830+
Self::Default => "Default",
831+
Self::DefaultCompose => "DefaultCompose",
832+
Self::All => "All",
833+
Self::AllCompose => "AllCompose",
834+
_ => "Unknown",
835+
}
836+
)
837+
}
838+
}
839+
840+
#[doc(hidden)]
841+
impl IntoGlib for NormalizeMode {
842+
type GlibType = ffi::GNormalizeMode;
843+
844+
fn into_glib(self) -> ffi::GNormalizeMode {
845+
match self {
846+
Self::Default => ffi::G_NORMALIZE_DEFAULT,
847+
Self::DefaultCompose => ffi::G_NORMALIZE_DEFAULT_COMPOSE,
848+
Self::All => ffi::G_NORMALIZE_ALL,
849+
Self::AllCompose => ffi::G_NORMALIZE_ALL_COMPOSE,
850+
Self::__Unknown(value) => value,
851+
}
852+
}
853+
}
854+
855+
#[doc(hidden)]
856+
impl FromGlib<ffi::GNormalizeMode> for NormalizeMode {
857+
unsafe fn from_glib(value: ffi::GNormalizeMode) -> Self {
858+
match value {
859+
ffi::G_NORMALIZE_DEFAULT => Self::Default,
860+
ffi::G_NORMALIZE_DEFAULT_COMPOSE => Self::DefaultCompose,
861+
ffi::G_NORMALIZE_ALL => Self::All,
862+
ffi::G_NORMALIZE_ALL_COMPOSE => Self::AllCompose,
863+
value => Self::__Unknown(value),
864+
}
865+
}
866+
}
867+
808868
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
809869
#[non_exhaustive]
810870
#[doc(alias = "GOptionArg")]

glib/src/auto/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub use self::enums::FileError;
4242
pub use self::enums::KeyFileError;
4343
pub use self::enums::LogWriterOutput;
4444
pub use self::enums::MarkupError;
45+
pub use self::enums::NormalizeMode;
4546
pub use self::enums::OptionArg;
4647
pub use self::enums::SeekType;
4748
pub use self::enums::TimeType;

glib/src/convert.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use std::{io, os::raw::c_char, path::PathBuf, ptr};
44

5-
use crate::{translate::*, ConvertError, Error, GStr, GString, Slice};
5+
use crate::{translate::*, ConvertError, Error, GStr, GString, NormalizeMode, Slice};
66

77
// rustdoc-stripper-ignore-next
88
/// A wrapper for [`ConvertError`](crate::ConvertError) that can hold an offset into the input
@@ -318,6 +318,74 @@ pub fn locale_to_utf8(opsysstring: &[u8]) -> Result<(crate::GString, usize), Cvt
318318
}
319319
}
320320

321+
#[doc(alias = "g_utf8_to_ucs4")]
322+
#[doc(alias = "g_utf8_to_ucs4_fast")]
323+
#[doc(alias = "utf8_to_ucs4")]
324+
pub fn utf8_to_utf32(str: impl AsRef<str>) -> Slice<char> {
325+
unsafe {
326+
let mut items_written = 0;
327+
328+
let str_as_utf32 = ffi::g_utf8_to_ucs4_fast(
329+
str.as_ref().as_ptr().cast::<c_char>(),
330+
str.as_ref().len() as _,
331+
&mut items_written,
332+
);
333+
334+
// NOTE: We assume that u32 and char have the same layout and trust that glib won't give us
335+
// invalid UTF-32 codepoints
336+
Slice::from_glib_full_num(str_as_utf32.cast::<char>(), items_written as usize)
337+
}
338+
}
339+
340+
#[doc(alias = "g_ucs4_to_utf8")]
341+
#[doc(alias = "ucs4_to_utf8")]
342+
pub fn utf32_to_utf8(str: impl AsRef<[char]>) -> GString {
343+
let mut items_read = 0;
344+
let mut items_written = 0;
345+
let mut error = ptr::null_mut();
346+
347+
unsafe {
348+
let str_as_utf8 = ffi::g_ucs4_to_utf8(
349+
str.as_ref().as_ptr().cast::<u32>(),
350+
str.as_ref().len() as _,
351+
&mut items_read,
352+
&mut items_written,
353+
&mut error,
354+
);
355+
356+
assert!(
357+
error.is_null(),
358+
"Rust `char` should always be convertible to UTF-8"
359+
);
360+
361+
GString::from_glib_full_num(str_as_utf8, items_written as usize)
362+
}
363+
}
364+
365+
#[doc(alias = "g_utf8_casefold")]
366+
#[doc(alias = "utf8_casefold")]
367+
pub fn casefold(str: impl AsRef<str>) -> GString {
368+
unsafe {
369+
let str = ffi::g_utf8_casefold(str.as_ref().as_ptr().cast(), str.as_ref().len() as isize);
370+
371+
from_glib_full(str)
372+
}
373+
}
374+
375+
#[doc(alias = "g_utf8_normalize")]
376+
#[doc(alias = "utf8_normalize")]
377+
pub fn normalize(str: impl AsRef<str>, mode: NormalizeMode) -> GString {
378+
unsafe {
379+
let str = ffi::g_utf8_normalize(
380+
str.as_ref().as_ptr().cast(),
381+
str.as_ref().len() as isize,
382+
mode.into_glib(),
383+
);
384+
385+
from_glib_full(str)
386+
}
387+
}
388+
321389
#[cfg(test)]
322390
mod tests {
323391
#[test]
@@ -350,4 +418,15 @@ mod tests {
350418
fn filename_charsets() {
351419
let _ = super::filename_charsets();
352420
}
421+
422+
#[test]
423+
fn utf8_and_utf32() {
424+
let utf32 = ['A', 'b', '🤔'];
425+
let utf8 = super::utf32_to_utf8(utf32);
426+
assert_eq!(utf8, "Ab🤔");
427+
428+
let utf8 = "🤔 ț";
429+
let utf32 = super::utf8_to_utf32(utf8);
430+
assert_eq!(utf32.as_slice(), &['🤔', ' ', 'ț']);
431+
}
353432
}

glib/src/gstring.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ impl GStr {
121121
pub fn as_c_str(&self) -> &CStr {
122122
unsafe { CStr::from_bytes_with_nul_unchecked(self.to_bytes_with_nul()) }
123123
}
124+
125+
#[doc(alias = "g_utf8_collate")]
126+
#[doc(alias = "utf8_collate")]
127+
pub fn collate(&self, other: impl AsRef<GStr>) -> Ordering {
128+
unsafe { ffi::g_utf8_collate(self.as_ptr(), other.as_ref().as_ptr()) }.cmp(&0)
129+
}
124130
}
125131

126132
// rustdoc-stripper-ignore-next

0 commit comments

Comments
 (0)