///|
let segment_magic : Bytes = b"MOONSEG\x00"
///|
let segment_format_version : UInt = 2U
///|
let legacy_segment_format_version : UInt = 1U
///|
fn encode_schema(buffer : @buffer.Buffer, schema : Schema?) -> Unit {
match schema {
None => write_bool(buffer, false)
Some(schema) => {
write_bool(buffer, true)
buffer.write_int_be(schema.field_count())
for field_index in 0.. name
None => abort("schema field disappeared during encoding")
}
let options = match schema.options(field_id) {
Some(options) => options
None => abort("schema options disappeared during encoding")
}
write_string(buffer, name)
write_bool(buffer, options.is_indexed())
write_bool(buffer, options.is_stored())
write_string(buffer, options.tokenizer_name())
}
}
}
}
///|
fn encode_payload(segment : Segment) -> Bytes {
let buffer = @buffer.Buffer()
encode_schema(buffer, segment.schema)
buffer.write_int_be(segment.document_count)
buffer.write_int_be(segment.indexed_terms.length())
for term_index in 0.. Bytes {
let buffer = @buffer.Buffer(
size_hint=segment_header_length + payload.length(),
)
buffer.write_bytes(segment_magic[:])
buffer.write_uint_be(segment_format_version)
buffer.write_int_be(payload.length())
buffer.write_uint_be(segment_checksum(payload))
buffer.write_bytes(payload[:])
buffer.to_bytes()
}
///|
pub fn encode_segment(segment : Segment) -> Bytes {
encode_container(encode_payload(segment))
}
///|
fn decode_schema(
decoder : SegmentDecoder,
version : UInt,
) -> Schema? raise PersistenceError {
if !decoder.read_bool("schema marker") {
return None
}
let field_count = decoder.read_count("schema field count")
let builder = SchemaBuilder::new()
for _ in 0.. Bool {
if field_id.value < 0 {
return false
}
match schema {
Some(schema) => field_id.value < schema.field_count()
None => true
}
}
///|
fn decode_postings(
decoder : SegmentDecoder,
document_count : Int,
) -> ReadOnlyArray[Posting] raise PersistenceError {
let posting_count = decoder.read_count("posting count")
let postings : Array[Posting] = []
let mut previous_doc_id = -1
for _ in 0..= 0 && doc_id < document_count && doc_id > previous_doc_id else {
raise PersistenceError::InvalidFormat("invalid posting doc id: \{doc_id}")
}
guard term_freq > 0 && position_count == term_freq else {
raise PersistenceError::InvalidFormat(
"term frequency and positions disagree",
)
}
let positions : Array[Int] = []
let mut previous_position = -1
for _ in 0..= 0 && position >= previous_position else {
raise PersistenceError::InvalidFormat("invalid term position")
}
positions.push(position)
previous_position = position
}
postings.push({
doc_id: DocId::new(doc_id),
term_freq,
positions: ReadOnlyArray::from_array(positions),
})
previous_doc_id = doc_id
}
ReadOnlyArray::from_array(postings)
}
///|
fn decode_stored_document(
decoder : SegmentDecoder,
schema : Schema?,
) -> StoredDocument raise PersistenceError {
let value_count = decoder.read_count("stored value count")
let field_ids : Array[FieldId] = []
let texts : Array[String] = []
for _ in 0.. ReadOnlyArray[FieldLength] raise PersistenceError {
let field_count = decoder.read_count("document field length count")
let lengths : Array[FieldLength] = []
for _ in 0.. entry.field_id == field_id) is None else {
raise PersistenceError::InvalidFormat("invalid field length entry")
}
lengths.push({ field_id, length })
}
ReadOnlyArray::from_array(lengths)
}
///|
fn decode_field_stats(
decoder : SegmentDecoder,
schema : Schema?,
document_count : Int,
) -> ReadOnlyArray[FieldStats] raise PersistenceError {
let field_count = decoder.read_count("field stats count")
let stats_entries : Array[FieldStats] = []
for _ in 0.. entry.field_id == field_id) is None else {
raise PersistenceError::InvalidFormat("invalid field statistics")
}
stats_entries.push({
field_id,
document_count: field_document_count,
total_length,
})
}
ReadOnlyArray::from_array(stats_entries)
}
///|
fn decode_payload(
payload : Bytes,
version : UInt,
) -> Segment raise PersistenceError {
let decoder = SegmentDecoder::new(payload)
let schema = decode_schema(decoder, version)
let document_count = decoder.read_count("document count")
let term_count = decoder.read_count("term count")
let terms : Array[Term] = []
let posting_lists : Array[ReadOnlyArray[Posting]] = []
for _ in 0.. existing == term) is None else {
raise PersistenceError::InvalidFormat("duplicate term")
}
terms.push(term)
posting_lists.push(decode_postings(decoder, document_count))
}
let stored_count = decoder.read_count("stored document count")
guard stored_count == document_count else {
raise PersistenceError::InvalidFormat("stored document count mismatch")
}
let stored_documents : Array[StoredDocument] = []
for _ in 0.. Segment raise PersistenceError {
guard bytes.length() >= segment_header_length else {
raise PersistenceError::InvalidFormat("truncated segment header")
}
for index in 0..