use crate::components::{
Arsc, Config, Header, Package, ResourceEntry, ResourceValue, Spec, Specs, StringPool, Type,
Value,
};
use crate::{Resources, Style, StyleSpan};
pub(in crate::writer) trait ConstByteSizing {
const SIZE: usize;
}
pub(in crate::writer) trait ByteSizing {
fn size(&self) -> usize;
}
impl<T: ConstByteSizing> ByteSizing for T {
fn size(&self) -> usize {
T::SIZE
}
}
impl ConstByteSizing for Value {
const SIZE: usize = 2 + 1 + 1 + 4; }
impl ByteSizing for ResourceValue {
fn size(&self) -> usize {
match self {
ResourceValue::Plain(_) => Value::SIZE,
ResourceValue::Bag { parent: _, values } => {
4 + 4 + values.len() * (4 + Value::SIZE)
}
}
}
}
impl ByteSizing for ResourceEntry {
fn size(&self) -> usize {
2 + 2 + 4 + self.value.size() }
}
impl ByteSizing for Config {
fn size(&self) -> usize {
Header::SIZE + 1 + 1 + 2 + 4 + 4 + self.id.len() + padding(self.id.len()) + self.resources.size()
}
}
impl ByteSizing for Resources {
fn size(&self) -> usize {
self.entry_count() * 4 + self.resources.iter().map(ByteSizing::size).sum::<usize>()
}
}
impl ConstByteSizing for Spec {
const SIZE: usize = 4; }
impl ByteSizing for Specs {
fn size(&self) -> usize {
Header::SIZE + 1 + 1 + 2 + 4 + self.specs.len() * Spec::SIZE
}
}
impl ByteSizing for Type {
fn size(&self) -> usize {
let parse_spec = self.specs.as_ref().map(ByteSizing::size).unwrap_or(0);
let parse_config = self.configs.iter().map(ByteSizing::size).sum::<usize>();
parse_spec + parse_config
}
}
impl ByteSizing for StringPool {
fn size(&self) -> usize {
let size = Header::SIZE + 5 * 4 + self.strings.len() * 4 + self.styles.len() * 4; let string_length = self
.strings
.iter()
.map(|s| {
if self.use_utf8() {
StringPool::utf8_string_size(s)
} else {
StringPool::utf16_string_size(s)
}
})
.sum::<usize>();
let string_padding = padding(string_length);
let style_size = if self.styles.is_empty() {
0
} else {
self.styles.iter().map(ByteSizing::size).sum::<usize>() + 8 };
size + string_length + string_padding + style_size
}
}
impl StringPool {
pub(crate) fn utf8_string_size(string: &str) -> usize {
let char_count = string.chars().count();
let char_count_bytes = if char_count <= 0x7F { 1 } else { 2 };
let byte_count = string.len();
let byte_count_bytes = if byte_count <= 0x7F { 1 } else { 2 };
char_count_bytes + byte_count_bytes + byte_count + 1 }
pub(crate) fn utf16_string_size(string: &str) -> usize {
let char_count = string.chars().count();
let char_count_bytes = if char_count <= 0x7FFF { 2 } else { 4 };
char_count_bytes + char_count * 2 + 2 }
}
impl ByteSizing for Style {
fn size(&self) -> usize {
self.spans.len() * StyleSpan::SIZE + 4
}
}
impl ConstByteSizing for StyleSpan {
const SIZE: usize = 4 + 4 + 4;
}
impl ByteSizing for Package {
fn size(&self) -> usize {
Header::SIZE + 4 + 256 + 5 * 4 + self.type_names.size()
+ self.types.iter().map(ByteSizing::size).sum::<usize>()
+ self.key_names.size()
}
}
impl ByteSizing for Arsc {
fn size(&self) -> usize {
Header::SIZE + 4 + self.global_string_pool.size()
+ self.packages.iter().map(ByteSizing::size).sum::<usize>()
}
}
impl ConstByteSizing for Header {
const SIZE: usize = 8;
}
pub(crate) fn padding(size: usize) -> usize {
(4 - size % 4) % 4
}