use std::io;
use crate::element::Element;
use crate::IonResult;
use digest::{FixedOutput, Output, Reset, Update};
use crate::ion_hash::representation::RepresentationEncoder;
use crate::ion_hash::type_qualifier::TypeQualifier;
use crate::ion_hash::Markers;
pub(crate) struct ElementHasher<D>
where
D: Update + FixedOutput + Reset + Clone + Default,
{
pub(crate) digest: D,
}
impl<D> ElementHasher<D>
where
D: Update + FixedOutput + Reset + Clone + Default,
{
pub(crate) fn new(digest: D) -> ElementHasher<D> {
ElementHasher { digest }
}
pub(crate) fn hash_element(mut self, elem: &Element) -> IonResult<Output<D>> {
self.update_serialized_bytes(elem)?;
Ok(self.digest.finalize_fixed())
}
pub(crate) fn update_serialized_bytes(&mut self, elem: &Element) -> IonResult<()> {
let has_annotations = !elem.annotations().is_empty();
if has_annotations {
self.mark_begin();
self.digest.update([0xE0]);
for ann in elem.annotations() {
self.mark_begin();
self.digest.update(match ann.text() {
None => [0x71],
Some(_) => [0x70],
});
self.write_repr_symbol(Some(ann))?;
self.mark_end();
}
}
self.mark_begin();
self.update_type_qualifier_and_representation(elem)?;
self.mark_end();
if has_annotations {
self.mark_end();
}
Ok(())
}
#[inline]
pub(crate) fn mark_begin(&mut self) {
self.digest.update([Markers::B]);
}
#[inline]
pub(crate) fn mark_end(&mut self) {
self.digest.update([Markers::E]);
}
pub(crate) fn update_type_qualifier_and_representation(
&mut self,
elem: &Element,
) -> IonResult<()> {
let tq = TypeQualifier::from_element(elem);
self.digest.update(tq.as_bytes());
self.update_with_representation(elem)
}
pub(crate) fn update_escaping(&mut self, data: impl AsRef<[u8]>) {
let mut escaped = vec![];
for byte in data.as_ref() {
if let Markers::B | Markers::E | Markers::ESC = *byte {
escaped.extend(&[Markers::ESC, *byte]);
} else {
escaped.extend(&[*byte]);
}
}
self.digest.update(escaped);
}
}
impl<D> io::Write for ElementHasher<D>
where
D: Update + FixedOutput + Reset + Clone + Default,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.update_escaping(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}