use std::io::Write;
use crate::error::Result;
use crate::index::lucene::codec::data_output::CodecOutput;
use crate::index::lucene::codec::postings::IndexOptions;
const CODEC_NAME: &str = "Lucene46FieldInfos";
const FORMAT_CURRENT: i32 = 0;
const IS_INDEXED: u8 = 0x1;
const STORE_OFFSETS_IN_POSTINGS: u8 = 0x4;
const OMIT_NORMS: u8 = 0x10;
const OMIT_TERM_FREQ_AND_POSITIONS: u8 = 0x40;
const OMIT_POSITIONS: u8 = 0x80;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DocValuesType {
Numeric,
Binary,
Sorted,
SortedSet,
}
impl DocValuesType {
const fn code(self) -> u8 {
match self {
Self::Numeric => 1,
Self::Binary => 2,
Self::Sorted => 3,
Self::SortedSet => 4,
}
}
}
#[derive(Clone, Debug)]
pub struct FieldInfo {
pub name: String,
pub number: i32,
pub indexed: bool,
pub options: IndexOptions,
pub omits_norms: bool,
pub doc_values: Option<DocValuesType>,
pub norms: Option<DocValuesType>,
pub doc_values_generation: i64,
pub attributes: Vec<(String, String)>,
}
impl FieldInfo {
fn bits(&self) -> u8 {
let mut bits = 0u8;
if self.omits_norms {
bits |= OMIT_NORMS;
}
if self.indexed {
bits |= IS_INDEXED;
bits |= match self.options {
IndexOptions::Documents => OMIT_TERM_FREQ_AND_POSITIONS,
IndexOptions::DocumentsAndFrequencies => OMIT_POSITIONS,
IndexOptions::DocumentsAndFrequenciesAndPositions => 0,
IndexOptions::DocumentsAndFrequenciesAndPositionsAndOffsets => {
STORE_OFFSETS_IN_POSTINGS
}
};
}
bits
}
fn packed_types(&self) -> u8 {
let doc_values = self.doc_values.map_or(0, DocValuesType::code);
let norms = self.norms.map_or(0, DocValuesType::code);
(norms << 4) | doc_values
}
}
pub fn write_field_infos<Sink: Write>(sink: Sink, fields: &[FieldInfo]) -> Result<Sink> {
let mut output = CodecOutput::new(sink);
output.write_header(CODEC_NAME, FORMAT_CURRENT)?;
output.write_vint(fields.len() as i32)?;
for field in fields {
output.write_string(&field.name)?;
output.write_vint(field.number)?;
output.write_byte(field.bits())?;
output.write_byte(field.packed_types())?;
output.write_long(field.doc_values_generation)?;
output.write_string_map(
field
.attributes
.iter()
.map(|(key, value)| (key.as_str(), value.as_str())),
)?;
}
Ok(output.into_inner())
}