fory-core 1.6.0-rc.1

Apache Fory: Blazingly fast multi-language serialization framework with trait objects and reference support.
Documentation
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::collections::BTreeMap;
use std::marker::PhantomData;

use crate::error::Error;

use super::bit_util::{bitmap_width, is_bit_set, round_up_to_word, slot_width};
use super::row::{Row, RowValue};

/// Backing-byte access shared by immutable Standard Row Format views.
pub trait RowView<'a> {
    /// Returns the complete encoded bytes bound to this view.
    fn as_bytes(&self) -> &'a [u8];

    /// Returns the number of encoded bytes bound to this view.
    #[inline]
    fn encoded_len(&self) -> usize {
        self.as_bytes().len()
    }
}

/// A zero-copy view over one Standard Row Format struct.
///
/// This type is public only because `ForyRow` views are generated in
/// downstream crates.
#[doc(hidden)]
#[derive(Clone, Copy)]
pub struct StructView<'a> {
    bytes: &'a [u8],
    bitmap_width: usize,
    num_fields: usize,
    fixed_end: usize,
}

impl<'a> StructView<'a> {
    /// Validates the fixed region for a struct with `num_fields` fields.
    pub fn new(bytes: &'a [u8], num_fields: usize) -> Result<Self, Error> {
        let bitmap_width = bitmap_width(num_fields)?;
        let slots_size = num_fields
            .checked_mul(8)
            .ok_or_else(|| Error::invalid_data("row fixed region size overflow"))?;
        let fixed_end = bitmap_width
            .checked_add(slots_size)
            .ok_or_else(|| Error::invalid_data("row fixed region size overflow"))?;
        ensure_range(bytes, 0, fixed_end)?;
        Ok(Self {
            bytes,
            bitmap_width,
            num_fields,
            fixed_end,
        })
    }

    /// Reads a field at its schema ordinal.
    pub fn get<T: RowValue>(&self, index: usize) -> Result<T::View<'a>, Error> {
        self.check_index(index)?;
        let bitmap = &self.bytes[..self.bitmap_width];
        if is_bit_set(bitmap, index) {
            return T::read_null();
        }

        let slot_offset = self
            .bitmap_width
            .checked_add(index * 8)
            .ok_or_else(|| Error::invalid_data("row field offset overflow"))?;
        let value = match T::FIXED_SIZE {
            Some(width) => {
                slot_width(Some(width))?;
                checked_slice(self.bytes, slot_offset, width)?
            }
            None => variable_slice(self.bytes, slot_offset, self.fixed_end)?,
        };
        T::read(value)
    }

    /// Returns whether a field's null bit is set.
    pub fn is_null(&self, index: usize) -> Result<bool, Error> {
        self.check_index(index)?;
        Ok(is_bit_set(&self.bytes[..self.bitmap_width], index))
    }

    fn check_index(&self, index: usize) -> Result<(), Error> {
        if index >= self.num_fields {
            Err(Error::buffer_out_of_bound(index, 1, self.num_fields))
        } else {
            Ok(())
        }
    }
}

impl<'a> RowView<'a> for StructView<'a> {
    #[inline]
    fn as_bytes(&self) -> &'a [u8] {
        self.bytes
    }
}

/// A zero-copy view over one Standard Row Format array.
pub struct ArrayView<'a, T: RowValue> {
    bytes: &'a [u8],
    num_elements: usize,
    bitmap_width: usize,
    header_size: usize,
    element_size: usize,
    fixed_end: usize,
    marker: PhantomData<T>,
}

impl<T: RowValue> Copy for ArrayView<'_, T> {}

impl<T: RowValue> Clone for ArrayView<'_, T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a, T: RowValue> ArrayView<'a, T> {
    pub(crate) fn new(bytes: &'a [u8]) -> Result<Self, Error> {
        let count = read_u64(bytes, 0)?;
        let num_elements = usize::try_from(count)
            .map_err(|_| Error::invalid_data("row array element count exceeds usize"))?;
        let bitmap_width = bitmap_width(num_elements)?;
        let header_size = 8usize
            .checked_add(bitmap_width)
            .ok_or_else(|| Error::invalid_data("row array header size overflow"))?;
        let element_size = slot_width(T::FIXED_SIZE)?;
        let element_bytes = num_elements
            .checked_mul(element_size)
            .ok_or_else(|| Error::invalid_data("row array fixed region size overflow"))?;
        let aligned_element_bytes = round_up_to_word(element_bytes)?;
        let fixed_end = header_size
            .checked_add(aligned_element_bytes)
            .ok_or_else(|| Error::invalid_data("row array fixed region size overflow"))?;
        ensure_range(bytes, 0, fixed_end)?;
        Ok(Self {
            bytes,
            num_elements,
            bitmap_width,
            header_size,
            element_size,
            fixed_end,
            marker: PhantomData,
        })
    }

    /// Returns the number of elements encoded in this array.
    pub fn len(&self) -> usize {
        self.num_elements
    }

    /// Returns true when this array contains no elements.
    pub fn is_empty(&self) -> bool {
        self.num_elements == 0
    }

    /// Returns an iterator that reads elements on demand.
    pub fn iter(&self) -> ArrayIter<'_, 'a, T> {
        ArrayIter {
            view: self,
            index: 0,
        }
    }

    /// Reads one array element without materializing the rest of the array.
    pub fn get(&self, index: usize) -> Result<T::View<'a>, Error> {
        self.check_index(index)?;
        let bitmap = &self.bytes[8..8 + self.bitmap_width];
        if is_bit_set(bitmap, index) {
            return T::read_null();
        }
        let slot_offset = self
            .header_size
            .checked_add(index * self.element_size)
            .ok_or_else(|| Error::invalid_data("row array element offset overflow"))?;
        let value = match T::FIXED_SIZE {
            Some(width) => checked_slice(self.bytes, slot_offset, width)?,
            None => variable_slice(self.bytes, slot_offset, self.fixed_end)?,
        };
        T::read(value)
    }

    /// Returns whether an element's null bit is set.
    pub fn is_null(&self, index: usize) -> Result<bool, Error> {
        self.check_index(index)?;
        let bitmap_start = 8;
        let bitmap = &self.bytes[bitmap_start..bitmap_start + self.bitmap_width];
        Ok(is_bit_set(bitmap, index))
    }

    fn check_index(&self, index: usize) -> Result<(), Error> {
        if index >= self.num_elements {
            Err(Error::buffer_out_of_bound(index, 1, self.num_elements))
        } else {
            Ok(())
        }
    }
}

impl<'a, T: RowValue> RowView<'a> for ArrayView<'a, T> {
    #[inline]
    fn as_bytes(&self) -> &'a [u8] {
        self.bytes
    }
}

/// An iterator over the elements of an [`ArrayView`].
pub struct ArrayIter<'view, 'row, T: RowValue> {
    view: &'view ArrayView<'row, T>,
    index: usize,
}

impl<'row, T: RowValue> Iterator for ArrayIter<'_, 'row, T> {
    type Item = Result<T::View<'row>, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index == self.view.len() {
            return None;
        }
        let index = self.index;
        self.index += 1;
        Some(self.view.get(index))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let remaining = self.view.len() - self.index;
        (remaining, Some(remaining))
    }
}

impl<T: RowValue> ExactSizeIterator for ArrayIter<'_, '_, T> {}

impl<'view, 'row, T: RowValue> IntoIterator for &'view ArrayView<'row, T> {
    type Item = Result<T::View<'row>, Error>;
    type IntoIter = ArrayIter<'view, 'row, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

/// A zero-copy view over one Standard Row Format map.
pub struct MapView<'a, K: RowValue, V: RowValue> {
    bytes: &'a [u8],
    keys: ArrayView<'a, K>,
    values: ArrayView<'a, V>,
}

impl<K: RowValue, V: RowValue> Copy for MapView<'_, K, V> {}

impl<K: RowValue, V: RowValue> Clone for MapView<'_, K, V> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a, K: RowValue, V: RowValue> MapView<'a, K, V> {
    pub(crate) fn new(bytes: &'a [u8]) -> Result<Self, Error> {
        let keys_size = read_u64(bytes, 0)?;
        let keys_size = usize::try_from(keys_size)
            .map_err(|_| Error::invalid_data("row map key array size exceeds usize"))?;
        let keys_end = 8usize
            .checked_add(keys_size)
            .ok_or_else(|| Error::invalid_data("row map key array size overflow"))?;
        ensure_range(bytes, 8, keys_size)?;
        let keys = ArrayView::<K>::new(&bytes[8..keys_end])?;
        let values = ArrayView::<V>::new(&bytes[keys_end..])?;
        if keys.len() != values.len() {
            return Err(Error::invalid_data(
                "row map key and value arrays have different lengths",
            ));
        }
        Ok(Self {
            bytes,
            keys,
            values,
        })
    }

    /// Returns the number of key-value pairs encoded in this map.
    pub fn len(&self) -> usize {
        self.keys.len()
    }

    /// Returns true when this map contains no key-value pairs.
    pub fn is_empty(&self) -> bool {
        self.keys.is_empty()
    }

    /// Reads the key at `index` without materializing the map.
    pub fn key(&self, index: usize) -> Result<K::View<'a>, Error> {
        self.keys.get(index)
    }

    /// Reads the value at `index` without materializing the map.
    pub fn value(&self, index: usize) -> Result<V::View<'a>, Error> {
        self.values.get(index)
    }

    /// Returns the map's key array.
    pub fn keys(&self) -> &ArrayView<'a, K> {
        &self.keys
    }

    /// Returns the map's value array.
    pub fn values(&self) -> &ArrayView<'a, V> {
        &self.values
    }

    /// Materializes this view as a `BTreeMap`.
    pub fn to_btree_map(
        &self,
    ) -> Result<BTreeMap<<K as RowValue>::View<'a>, <V as RowValue>::View<'a>>, Error>
    where
        <K as RowValue>::View<'a>: Ord,
    {
        let mut map = BTreeMap::new();
        for index in 0..self.keys.len() {
            map.insert(self.keys.get(index)?, self.values.get(index)?);
        }
        Ok(map)
    }
}

impl<'a, K: RowValue, V: RowValue> RowView<'a> for MapView<'a, K, V> {
    #[inline]
    fn as_bytes(&self) -> &'a [u8] {
        self.bytes
    }
}

fn variable_slice(bytes: &[u8], slot_offset: usize, fixed_end: usize) -> Result<&[u8], Error> {
    let offset_and_size = read_u64(bytes, slot_offset)?;
    let relative_offset = usize::try_from(offset_and_size >> 32)
        .map_err(|_| Error::invalid_data("row variable offset exceeds usize"))?;
    let size = (offset_and_size as u32) as usize;
    if relative_offset < fixed_end {
        return Err(Error::invalid_data(
            "row variable value overlaps the fixed region",
        ));
    }
    checked_slice(bytes, relative_offset, size)
}

fn read_u64(bytes: &[u8], offset: usize) -> Result<u64, Error> {
    let value = checked_slice(bytes, offset, 8)?;
    let mut array = [0u8; 8];
    array.copy_from_slice(value);
    Ok(u64::from_le_bytes(array))
}

fn checked_slice(bytes: &[u8], offset: usize, size: usize) -> Result<&[u8], Error> {
    let end = offset
        .checked_add(size)
        .ok_or_else(|| Error::buffer_out_of_bound(offset, size, bytes.len()))?;
    if end > bytes.len() {
        Err(Error::buffer_out_of_bound(offset, size, bytes.len()))
    } else {
        Ok(&bytes[offset..end])
    }
}

fn ensure_range(bytes: &[u8], offset: usize, size: usize) -> Result<(), Error> {
    checked_slice(bytes, offset, size).map(|_| ())
}

/// Decodes a Standard Row Format struct, array, or map root.
pub fn from_row<T: Row>(bytes: &[u8]) -> Result<T::View<'_>, Error> {
    T::read(bytes)
}