Skip to main content

lance_encoding/encodings/physical/
constant.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4//! Routines for compressing and decompressing constant-encoded data
5
6use crate::{
7    buffer::LanceBuffer,
8    compression::{BlockDecompressor, FixedPerValueDecompressor, require_no_block_payload},
9    data::{AllNullDataBlock, ConstantDataBlock, DataBlock, FixedWidthDataBlock},
10};
11
12use lance_core::Result;
13
14/// A decompressor for constant-encoded data
15#[derive(Debug)]
16pub struct ConstantDecompressor {
17    scalar: Option<LanceBuffer>,
18}
19
20impl ConstantDecompressor {
21    pub fn new(scalar: Option<LanceBuffer>) -> Self {
22        Self { scalar }
23    }
24}
25
26impl BlockDecompressor for ConstantDecompressor {
27    fn decompress(&self, data: Option<LanceBuffer>, num_values: u64) -> Result<DataBlock> {
28        require_no_block_payload(data, "Constant")?;
29        if let Some(scalar) = self.scalar.clone() {
30            Ok(DataBlock::Constant(ConstantDataBlock {
31                data: scalar,
32                num_values,
33            }))
34        } else {
35            Ok(DataBlock::AllNull(AllNullDataBlock { num_values }))
36        }
37    }
38
39    fn requires_payload(&self) -> bool {
40        false
41    }
42}
43
44impl FixedPerValueDecompressor for ConstantDecompressor {
45    fn decompress(&self, _data: FixedWidthDataBlock, num_values: u64) -> Result<DataBlock> {
46        if let Some(scalar) = self.scalar.clone() {
47            Ok(DataBlock::Constant(ConstantDataBlock {
48                data: scalar,
49                num_values,
50            }))
51        } else {
52            Ok(DataBlock::AllNull(AllNullDataBlock { num_values }))
53        }
54    }
55
56    fn bits_per_value(&self) -> u64 {
57        self.scalar
58            .as_ref()
59            .map(|s| s.len() as u64 * 8)
60            .unwrap_or(0)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn block_constant_requires_no_payload() {
70        let decompressor = ConstantDecompressor::new(None);
71
72        assert!(!decompressor.requires_payload());
73        assert!(matches!(
74            BlockDecompressor::decompress(&decompressor, None, 3).unwrap(),
75            DataBlock::AllNull(AllNullDataBlock { num_values: 3 })
76        ));
77        assert!(
78            BlockDecompressor::decompress(&decompressor, Some(LanceBuffer::empty()), 3).is_err()
79        );
80    }
81}