use crate::error::{Error, Result};
use indexmap::IndexMap;
pub type ObjectId = (u32, u16);
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StringFormat {
Literal,
Hexadecimal,
}
#[derive(Debug, Clone)]
pub enum Object {
Boolean(bool),
Integer(i64),
Real(f32),
Name(Vec<u8>),
String(Vec<u8>, StringFormat),
Array(Vec<Object>),
Dictionary(Dictionary),
Stream(Stream),
Null,
Reference(ObjectId),
}
impl PartialEq for Object {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Boolean(a), Self::Boolean(b)) => a == b,
(Self::Integer(a), Self::Integer(b)) => a == b,
(Self::Real(a), Self::Real(b)) => a.to_bits() == b.to_bits(),
(Self::Name(a), Self::Name(b)) => a == b,
(Self::String(a, af), Self::String(b, bf)) => a == b && af == bf,
(Self::Array(a), Self::Array(b)) => a == b,
(Self::Dictionary(a), Self::Dictionary(b)) => a == b,
(Self::Stream(a), Self::Stream(b)) => a.dict == b.dict,
(Self::Null, Self::Null) => true,
(Self::Reference(a), Self::Reference(b)) => a == b,
_ => false,
}
}
}
impl Object {
pub fn type_name(&self) -> &'static str {
match self {
Self::Boolean(_) => "Boolean",
Self::Integer(_) => "Integer",
Self::Real(_) => "Real",
Self::Name(_) => "Name",
Self::String(_, _) => "String",
Self::Array(_) => "Array",
Self::Dictionary(_) => "Dictionary",
Self::Stream(_) => "Stream",
Self::Null => "Null",
Self::Reference(_) => "Reference",
}
}
pub fn as_name(&self) -> Result<&[u8]> {
match self {
Self::Name(n) => Ok(n),
other => Err(Error::Type {
expected: "Name",
found: other.type_name(),
}),
}
}
pub fn as_str(&self) -> Result<&[u8]> {
match self {
Self::String(b, _) => Ok(b),
other => Err(Error::Type {
expected: "String",
found: other.type_name(),
}),
}
}
pub fn as_i64(&self) -> Result<i64> {
match self {
Self::Integer(n) => Ok(*n),
other => Err(Error::Type {
expected: "Integer",
found: other.type_name(),
}),
}
}
pub fn as_f32(&self) -> Result<f32> {
match self {
Self::Real(n) => Ok(*n),
other => Err(Error::Type {
expected: "Real",
found: other.type_name(),
}),
}
}
pub fn as_float(&self) -> Result<f32> {
match self {
Self::Integer(n) => Ok(*n as f32),
Self::Real(n) => Ok(*n),
other => Err(Error::Type {
expected: "Numeric",
found: other.type_name(),
}),
}
}
pub fn as_array(&self) -> Result<&Vec<Object>> {
match self {
Self::Array(a) => Ok(a),
other => Err(Error::Type {
expected: "Array",
found: other.type_name(),
}),
}
}
pub fn as_dict(&self) -> Result<&Dictionary> {
match self {
Self::Dictionary(d) => Ok(d),
Self::Stream(s) => Ok(&s.dict),
other => Err(Error::Type {
expected: "Dictionary",
found: other.type_name(),
}),
}
}
pub fn as_stream(&self) -> Result<&Stream> {
match self {
Self::Stream(s) => Ok(s),
other => Err(Error::Type {
expected: "Stream",
found: other.type_name(),
}),
}
}
pub fn as_reference(&self) -> Result<ObjectId> {
match self {
Self::Reference(id) => Ok(*id),
other => Err(Error::Type {
expected: "Reference",
found: other.type_name(),
}),
}
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Dictionary {
entries: IndexMap<Vec<u8>, Object>,
}
impl Dictionary {
pub fn new() -> Self {
Self::default()
}
pub fn set<K, V>(&mut self, key: K, value: V)
where
K: Into<Vec<u8>>,
V: Into<Object>,
{
self.entries.insert(key.into(), value.into());
}
pub fn get(&self, key: &[u8]) -> Result<&Object> {
self.entries
.get(key)
.ok_or_else(|| Error::DictKey(String::from_utf8_lossy(key).into_owned()))
}
pub fn get_optional(&self, key: &[u8]) -> Option<&Object> {
self.entries.get(key)
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn iter(&self) -> indexmap::map::Iter<'_, Vec<u8>, Object> {
self.entries.iter()
}
pub fn iter_mut(&mut self) -> indexmap::map::IterMut<'_, Vec<u8>, Object> {
self.entries.iter_mut()
}
pub fn keys(&self) -> indexmap::map::Keys<'_, Vec<u8>, Object> {
self.entries.keys()
}
pub fn has_type(&self, name: &[u8]) -> bool {
matches!(
self.entries.get(b"Type".as_slice()),
Some(Object::Name(n)) if n == name
)
}
}
#[derive(Debug, Clone)]
pub struct Stream {
pub dict: Dictionary,
pub content: Vec<u8>,
pub start_position: Option<usize>,
}
impl Stream {
pub fn new(dict: Dictionary, content: Vec<u8>) -> Self {
Self {
dict,
content,
start_position: None,
}
}
}
impl From<bool> for Object {
fn from(v: bool) -> Self {
Self::Boolean(v)
}
}
impl From<i64> for Object {
fn from(v: i64) -> Self {
Self::Integer(v)
}
}
impl From<i32> for Object {
fn from(v: i32) -> Self {
Self::Integer(v as i64)
}
}
impl From<f32> for Object {
fn from(v: f32) -> Self {
Self::Real(v)
}
}
impl From<Vec<u8>> for Object {
fn from(v: Vec<u8>) -> Self {
Self::String(v, StringFormat::Literal)
}
}
impl From<&str> for Object {
fn from(v: &str) -> Self {
Self::Name(v.as_bytes().to_vec())
}
}
impl From<Vec<Object>> for Object {
fn from(v: Vec<Object>) -> Self {
Self::Array(v)
}
}
impl From<Dictionary> for Object {
fn from(v: Dictionary) -> Self {
Self::Dictionary(v)
}
}
impl From<Stream> for Object {
fn from(v: Stream) -> Self {
Self::Stream(v)
}
}