blob: aea8c86e944f65c582c80486ad4da91fa8e7aac7 [file]
// 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.
//! Row decoder for deserializing binary row formats.
//!
//! Mirrors the Java org.apache.fluss.row.decode package.
use crate::error::{Error, Result};
use crate::metadata::{KvFormat, RowType};
use crate::row::compacted::{CompactedRow, CompactedRowDeserializer};
use std::sync::Arc;
/// Decoder for creating BinaryRow from bytes.
///
/// This trait provides an abstraction for decoding different row formats
/// (COMPACTED, INDEXED, etc.) from binary data.
///
/// Reference: org.apache.fluss.row.decode.RowDecoder
pub trait RowDecoder: Send + Sync {
/// Decode bytes into a CompactedRow.
///
/// The lifetime 'a ties the returned row to the input data, ensuring
/// the data remains valid as long as the row is used.
fn decode<'a>(&self, data: &'a [u8]) -> CompactedRow<'a>;
}
/// Decoder for CompactedRow format.
///
/// Uses the existing CompactedRow infrastructure for decoding.
/// This is a thin wrapper that implements the RowDecoder trait.
///
/// Reference: org.apache.fluss.row.decode.CompactedRowDecoder
pub struct CompactedRowDecoder {
field_count: usize,
deserializer: Arc<CompactedRowDeserializer<'static>>,
}
impl CompactedRowDecoder {
/// Create a new CompactedRowDecoder with the given row type.
pub fn new(row_type: RowType) -> Self {
let field_count = row_type.fields().len();
let deserializer = Arc::new(CompactedRowDeserializer::new_from_owned(row_type));
Self {
field_count,
deserializer,
}
}
}
impl RowDecoder for CompactedRowDecoder {
fn decode<'a>(&self, data: &'a [u8]) -> CompactedRow<'a> {
// Use existing CompactedRow::deserialize() infrastructure
CompactedRow::deserialize(Arc::clone(&self.deserializer), self.field_count, data)
}
}
/// Factory for creating RowDecoders based on KvFormat.
///
/// Reference: org.apache.fluss.row.decode.RowDecoder.create()
pub struct RowDecoderFactory;
impl RowDecoderFactory {
/// Create a RowDecoder for the given format and row type.
pub fn create(kv_format: KvFormat, row_type: RowType) -> Result<Arc<dyn RowDecoder>> {
match kv_format {
KvFormat::COMPACTED => Ok(Arc::new(CompactedRowDecoder::new(row_type))),
KvFormat::INDEXED => Err(Error::UnsupportedOperation {
message: "INDEXED format is not yet supported".to_string(),
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::metadata::DataTypes;
use crate::row::InternalRow;
use crate::row::binary::BinaryWriter;
use crate::row::compacted::CompactedRowWriter;
#[test]
fn test_compacted_row_decoder() {
// Write a CompactedRow
let mut writer = CompactedRowWriter::new(2);
writer.write_int(42);
writer.write_string("hello");
let data = writer.to_bytes();
// Create decoder with RowType
let row_type = RowType::with_data_types(vec![DataTypes::int(), DataTypes::string()]);
let decoder = CompactedRowDecoder::new(row_type);
// Decode
let row = decoder.decode(&data);
// Verify
assert_eq!(row.get_field_count(), 2);
assert_eq!(row.get_int(0).unwrap(), 42);
assert_eq!(row.get_string(1).unwrap(), "hello");
}
#[test]
fn test_row_decoder_factory() {
let row_type = RowType::with_data_types(vec![DataTypes::int(), DataTypes::string()]);
let decoder = RowDecoderFactory::create(KvFormat::COMPACTED, row_type).unwrap();
// Write a row
let mut writer = CompactedRowWriter::new(2);
writer.write_int(100);
writer.write_string("world");
let data = writer.to_bytes();
// Decode
let row = decoder.decode(&data);
// Verify
assert_eq!(row.get_int(0).unwrap(), 100);
assert_eq!(row.get_string(1).unwrap(), "world");
}
}