|
| 1 | +use super::{sys, FcErr}; |
| 2 | +use std::convert::TryInto; |
| 3 | +use std::ffi::CStr; |
| 4 | +use std::ptr; |
| 5 | +use std::ptr::NonNull; |
| 6 | + |
| 7 | +unsafe fn get_string<'a>( |
| 8 | + pat: *mut sys::FcPattern, |
| 9 | + ty: *const libc::c_char, |
| 10 | + idx: libc::c_int, |
| 11 | +) -> Result<&'a CStr, FcErr> { |
| 12 | + let mut str = ptr::null(); |
| 13 | + match unsafe { sys::FcPatternGetString(pat, ty, idx, &mut str) }.try_into() { |
| 14 | + Ok(err) => Err(err), |
| 15 | + Err(_) => Ok(CStr::from_ptr(str)), |
| 16 | + } |
| 17 | +} |
| 18 | + |
| 19 | +unsafe fn get_int( |
| 20 | + pat: *mut sys::FcPattern, |
| 21 | + ty: *const libc::c_char, |
| 22 | + idx: libc::c_int, |
| 23 | +) -> Result<i32, FcErr> { |
| 24 | + let mut int = 0; |
| 25 | + match unsafe { sys::FcPatternGetInteger(pat, ty, idx, &mut int) }.try_into() { |
| 26 | + Ok(err) => Err(err), |
| 27 | + Err(_) => Ok(int as i32), |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +pub trait PatParam { |
| 32 | + type Output<'a>; |
| 33 | + fn get(pat: &Pattern, idx: usize) -> Result<Self::Output<'_>, FcErr>; |
| 34 | +} |
| 35 | + |
| 36 | +pub struct File(()); |
| 37 | + |
| 38 | +impl PatParam for File { |
| 39 | + type Output<'a> = &'a CStr; |
| 40 | + |
| 41 | + fn get(pat: &Pattern, idx: usize) -> Result<Self::Output<'_>, FcErr> { |
| 42 | + unsafe { get_string(pat.0.as_ptr(), sys::FC_FILE, idx as libc::c_int) } |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +pub struct Family(()); |
| 47 | + |
| 48 | +impl PatParam for Family { |
| 49 | + type Output<'a> = &'a CStr; |
| 50 | + |
| 51 | + fn get(pat: &Pattern, idx: usize) -> Result<Self::Output<'_>, FcErr> { |
| 52 | + unsafe { get_string(pat.0.as_ptr(), sys::FC_FAMILY, idx as libc::c_int) } |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +pub struct FullName(()); |
| 57 | + |
| 58 | +impl PatParam for FullName { |
| 59 | + type Output<'a> = &'a CStr; |
| 60 | + |
| 61 | + fn get(pat: &Pattern, idx: usize) -> Result<Self::Output<'_>, FcErr> { |
| 62 | + unsafe { get_string(pat.0.as_ptr(), sys::FC_FULLNAME, idx as libc::c_int) } |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +pub struct Style(()); |
| 67 | + |
| 68 | +impl PatParam for Style { |
| 69 | + type Output<'a> = &'a CStr; |
| 70 | + |
| 71 | + fn get(pat: &Pattern, idx: usize) -> Result<Self::Output<'_>, FcErr> { |
| 72 | + unsafe { get_string(pat.0.as_ptr(), sys::FC_STYLE, idx as libc::c_int) } |
| 73 | + } |
| 74 | +} |
| 75 | + |
| 76 | +pub struct Index(()); |
| 77 | + |
| 78 | +impl PatParam for Index { |
| 79 | + type Output<'a> = i32; |
| 80 | + |
| 81 | + fn get(pat: &Pattern, idx: usize) -> Result<Self::Output<'_>, FcErr> { |
| 82 | + unsafe { get_int(pat.0.as_ptr(), sys::FC_INDEX, idx as libc::c_int) } |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +#[derive(Clone, PartialEq, Eq, Hash)] |
| 87 | +#[repr(transparent)] |
| 88 | +pub struct Pattern(NonNull<sys::FcPattern>); |
| 89 | + |
| 90 | +impl Pattern { |
| 91 | + pub unsafe fn from_raw(ptr: *mut sys::FcPattern) -> Option<Pattern> { |
| 92 | + NonNull::new(ptr).map(Pattern) |
| 93 | + } |
| 94 | + |
| 95 | + pub fn into_raw(self) -> *mut sys::FcPattern { |
| 96 | + self.0.as_ptr() |
| 97 | + } |
| 98 | + |
| 99 | + pub fn from_name(name: &CStr) -> Option<Pattern> { |
| 100 | + let raw = unsafe { sys::FcNameParse(name.as_ptr()) }; |
| 101 | + NonNull::new(raw).map(Pattern) |
| 102 | + } |
| 103 | + |
| 104 | + pub fn get<T: PatParam>(&self, idx: usize) -> Result<T::Output<'_>, FcErr> { |
| 105 | + T::get(self, idx) |
| 106 | + } |
| 107 | +} |
0 commit comments