#![allow(dead_code)]
use super::tag::TagType;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::{slice, str};
#[derive(Debug)]
pub enum TagData<'hdr> {
Null,
Char(&'hdr [u8]),
Int8(&'hdr [i8]),
Int16(&'hdr [i16]),
Int32(&'hdr [i32]),
Int64(&'hdr [i64]),
Str(&'hdr str),
StrArray(Vec<&'hdr str>),
I18NStr(Vec<&'hdr str>),
Bin(&'hdr [u8]),
}
impl<'hdr> TagData<'hdr> {
pub(crate) unsafe fn char(td: &librpm_sys::rpmtd_s) -> Self {
assert_eq!(td.type_, TagType::CHAR as u32);
let data = unsafe { slice::from_raw_parts(td.data as *const u8, td.count as usize) };
TagData::Char(data)
}
pub(crate) unsafe fn int8(td: &librpm_sys::rpmtd_s) -> Self {
assert_eq!(td.type_, TagType::INT8 as u32);
let data = unsafe { slice::from_raw_parts(td.data as *const i8, td.count as usize) };
TagData::Int8(data)
}
pub(crate) unsafe fn int16(td: &librpm_sys::rpmtd_s) -> Self {
assert_eq!(td.type_, TagType::INT16 as u32);
let data = unsafe { slice::from_raw_parts(td.data as *const i16, td.count as usize) };
TagData::Int16(data)
}
pub(crate) unsafe fn int32(td: &librpm_sys::rpmtd_s) -> Self {
assert_eq!(td.type_, TagType::INT32 as u32);
let data = unsafe { slice::from_raw_parts(td.data as *const i32, td.count as usize) };
TagData::Int32(data)
}
pub(crate) unsafe fn int64(td: &librpm_sys::rpmtd_s) -> Self {
assert_eq!(td.type_, TagType::INT64 as u32);
let data = unsafe { slice::from_raw_parts(td.data as *const i64, td.count as usize) };
TagData::Int64(data)
}
pub(crate) unsafe fn string(td: &librpm_sys::rpmtd_s) -> Self {
assert_eq!(td.type_, TagType::STRING as u32);
let cstr = unsafe { CStr::from_ptr(td.data as *const c_char) };
TagData::Str(str::from_utf8(cstr.to_bytes()).unwrap_or_else(|e| {
panic!(
"failed to decode RPM_STRING_TYPE as UTF-8 (tag: {}): {}",
td.tag, e
);
}))
}
pub(crate) unsafe fn string_array(td: &mut librpm_sys::rpmtd_s) -> Self {
assert_eq!(td.type_, TagType::STRING_ARRAY as u32);
let mut result = Vec::new();
loop {
let cstr = unsafe { librpm_sys::rpmtdNextString(td) };
if cstr.is_null() {
break;
}
let cstr = unsafe { CStr::from_ptr(cstr as *const c_char) };
result.push(str::from_utf8(cstr.to_bytes()).unwrap_or_else(|e| {
panic!(
"failed to decode an item from RPM_STRING_ARRAY as UTF-8 (tag: {}): {}",
td.tag, e
);
}));
}
TagData::StrArray(result)
}
pub(crate) unsafe fn i18n_string(td: &mut librpm_sys::rpmtd_s) -> Self {
assert_eq!(td.type_, TagType::I18NSTRING as u32);
let mut result = Vec::new();
loop {
let cstr = unsafe { librpm_sys::rpmtdNextString(td) };
if cstr.is_null() {
break;
}
let cstr = unsafe { CStr::from_ptr(cstr as *const c_char) };
result.push(str::from_utf8(cstr.to_bytes()).unwrap_or_else(|e| {
panic!(
"failed to decode an item from RPM_I18NSTRING_TYPE as UTF-8 (tag: {}): {}",
td.tag, e
);
}));
}
TagData::I18NStr(result)
}
pub(crate) unsafe fn bin(td: &librpm_sys::rpmtd_s) -> Self {
assert_eq!(td.type_, TagType::BIN as u32);
assert!(
!td.data.is_null(),
"rpmtd.data is NULL! (tag type: {})",
td.tag
);
assert_ne!(
td.type_,
TagType::NULL as u32,
"can't get slice of NULL data (tag type: {})",
td.tag
);
let bin = unsafe { slice::from_raw_parts(td.data as *const u8, td.count as usize) };
TagData::Bin(bin)
}
pub fn is_null(&self) -> bool {
matches!(*self, TagData::Null)
}
pub fn as_char(&self) -> Option<u8> {
self.as_char_array().and_then(|s| s.first().copied())
}
pub fn as_char_array(&self) -> Option<&'hdr [u8]> {
match *self {
TagData::Char(c) => Some(c),
_ => None,
}
}
pub fn is_char(&self) -> bool {
self.as_char_array().is_some()
}
pub fn as_int8(&self) -> Option<i8> {
self.as_int8_array().and_then(|s| s.first().copied())
}
pub fn as_int8_array(&self) -> Option<&'hdr [i8]> {
match *self {
TagData::Int8(i) => Some(i),
_ => None,
}
}
pub fn is_int8(&self) -> bool {
self.as_int8_array().is_some()
}
pub fn as_int16(&self) -> Option<i16> {
self.as_int16_array().and_then(|s| s.first().copied())
}
pub fn as_int16_array(&self) -> Option<&'hdr [i16]> {
match *self {
TagData::Int16(i) => Some(i),
_ => None,
}
}
pub fn is_int16(&self) -> bool {
self.as_int16_array().is_some()
}
pub fn as_int32(&self) -> Option<i32> {
self.as_int32_array().and_then(|s| s.first().copied())
}
pub fn as_int32_array(&self) -> Option<&'hdr [i32]> {
match *self {
TagData::Int32(i) => Some(i),
_ => None,
}
}
pub fn is_int32(&self) -> bool {
self.as_int32_array().is_some()
}
pub fn as_int64(&self) -> Option<i64> {
self.as_int64_array().and_then(|s| s.first().copied())
}
pub fn as_int64_array(&self) -> Option<&'hdr [i64]> {
match *self {
TagData::Int64(i) => Some(i),
_ => None,
}
}
pub fn is_int64(&self) -> bool {
self.as_int64_array().is_some()
}
pub fn as_str(&self) -> Option<&'hdr str> {
match self {
TagData::Str(s) => Some(s),
TagData::I18NStr(s) => s.first().copied(),
_ => None,
}
}
pub fn is_str(&self) -> bool {
self.as_str().is_some()
}
pub fn as_i18n_str_array(&self) -> Option<&[&'hdr str]> {
match self {
TagData::I18NStr(sa) => Some(&sa[..]),
_ => None,
}
}
pub fn as_str_array(&self) -> Option<&[&'hdr str]> {
match *self {
TagData::StrArray(ref sa) => Some(&sa[..]),
_ => None,
}
}
pub fn is_str_array(&self) -> bool {
self.as_str_array().is_some()
}
pub fn as_bytes(&self) -> Option<&[u8]> {
match *self {
TagData::Bin(b) => Some(b),
_ => None,
}
}
pub fn is_bytes(&self) -> bool {
self.as_bytes().is_some()
}
}