use std::fmt;
use std::sync::Arc;
use bytes::Bytes;
use ruststream::{BuildBatchContext, BuildContext, Field, Str};
use crate::message::KafkaMessage;
use crate::record::Shared;
use crate::seek::{KafkaPosition, KafkaSeeker};
#[derive(Clone)]
pub struct KafkaContext {
shared: Arc<Shared>,
topic: Option<Str>,
partition: i32,
offset: i64,
timestamp_millis: Option<i64>,
key: Option<Bytes>,
}
impl KafkaContext {
#[must_use]
pub fn topic(&self) -> &str {
self.topic_name()
}
fn topic_name(&self) -> &Str {
self.shared.topic(self.topic.as_ref())
}
#[must_use]
pub fn partition(&self) -> i32 {
self.partition
}
#[must_use]
pub fn offset(&self) -> i64 {
self.offset
}
#[must_use]
pub fn timestamp_millis(&self) -> Option<i64> {
self.timestamp_millis
}
#[must_use]
pub fn key(&self) -> Option<&[u8]> {
self.key.as_deref()
}
pub(crate) fn shared_topic(&self) -> Str {
self.topic_name().clone()
}
pub(crate) fn shared_key(&self) -> Option<Bytes> {
self.key.clone()
}
#[must_use]
pub fn position(&self) -> KafkaPosition {
KafkaPosition::topic_offset(self.topic(), self.partition, self.offset)
}
#[must_use]
pub fn seeker(&self) -> &KafkaSeeker {
&self.shared.seeker
}
}
impl fmt::Debug for KafkaContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("KafkaContext")
.field("topic", self.topic_name())
.field("partition", &self.partition)
.field("offset", &self.offset)
.field("timestamp_millis", &self.timestamp_millis)
.field("key", &self.key)
.field("seeker", &self.shared.seeker)
.finish()
}
}
impl BuildContext<KafkaMessage> for KafkaContext {
fn build(msg: &KafkaMessage) -> Self {
Self {
shared: msg.shared_handle(),
topic: msg.own_topic(),
partition: msg.partition(),
offset: msg.offset(),
timestamp_millis: msg.timestamp_millis(),
key: msg.key().map(Bytes::copy_from_slice),
}
}
}
#[derive(Debug, Clone)]
pub struct KafkaBatchContext {
seeker: Arc<KafkaSeeker>,
}
impl KafkaBatchContext {
#[must_use]
pub fn seeker(&self) -> &KafkaSeeker {
&self.seeker
}
}
impl BuildBatchContext<KafkaMessage> for KafkaBatchContext {
fn build(first: &KafkaMessage) -> Self {
Self {
seeker: first.seeker_handle(),
}
}
}
pub mod keys {
use bytes::Bytes;
use ruststream::{ContextField, Str};
use super::{Field, KafkaBatchContext, KafkaContext, KafkaPosition, KafkaSeeker};
use crate::eos::SourceOffset;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Topic;
impl Field<KafkaContext> for Topic {
type Value<'a> = &'a Str;
fn get(self, src: &KafkaContext) -> &Str {
src.topic_name()
}
}
impl ContextField for Topic {
type Context = KafkaContext;
type Value = Str;
fn read(self, src: &KafkaContext) -> Str {
src.shared_topic()
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Partition;
impl Field<KafkaContext> for Partition {
type Value<'a> = i32;
fn get(self, src: &KafkaContext) -> i32 {
src.partition()
}
}
impl ContextField for Partition {
type Context = KafkaContext;
type Value = i32;
fn read(self, src: &KafkaContext) -> i32 {
src.partition()
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Offset;
impl Field<KafkaContext> for Offset {
type Value<'a> = i64;
fn get(self, src: &KafkaContext) -> i64 {
src.offset()
}
}
impl ContextField for Offset {
type Context = KafkaContext;
type Value = i64;
fn read(self, src: &KafkaContext) -> i64 {
src.offset()
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct TimestampMillis;
impl Field<KafkaContext> for TimestampMillis {
type Value<'a> = Option<i64>;
fn get(self, src: &KafkaContext) -> Option<i64> {
src.timestamp_millis()
}
}
impl ContextField for TimestampMillis {
type Context = KafkaContext;
type Value = Option<i64>;
fn read(self, src: &KafkaContext) -> Option<i64> {
src.timestamp_millis()
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Key;
impl Field<KafkaContext> for Key {
type Value<'a> = Option<&'a [u8]>;
fn get(self, src: &KafkaContext) -> Option<&[u8]> {
src.key()
}
}
impl ContextField for Key {
type Context = KafkaContext;
type Value = Option<Bytes>;
fn read(self, src: &KafkaContext) -> Option<Bytes> {
src.shared_key()
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Source;
impl Field<KafkaContext> for Source {
type Value<'a> = SourceOffset;
fn get(self, src: &KafkaContext) -> SourceOffset {
SourceOffset::new(src.shared_topic(), src.partition(), src.offset())
}
}
impl ContextField for Source {
type Context = KafkaContext;
type Value = SourceOffset;
fn read(self, src: &KafkaContext) -> SourceOffset {
SourceOffset::new(src.shared_topic(), src.partition(), src.offset())
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Position;
impl Field<KafkaContext> for Position {
type Value<'a> = KafkaPosition;
fn get(self, src: &KafkaContext) -> KafkaPosition {
src.position()
}
}
impl ContextField for Position {
type Context = KafkaContext;
type Value = KafkaPosition;
fn read(self, src: &KafkaContext) -> KafkaPosition {
src.position()
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct SeekHandle;
impl Field<KafkaContext> for SeekHandle {
type Value<'a> = &'a KafkaSeeker;
fn get(self, src: &KafkaContext) -> &KafkaSeeker {
src.seeker()
}
}
impl ContextField for SeekHandle {
type Context = KafkaContext;
type Value = KafkaSeeker;
fn read(self, src: &KafkaContext) -> KafkaSeeker {
src.seeker().clone()
}
}
impl Field<KafkaBatchContext> for SeekHandle {
type Value<'a> = &'a KafkaSeeker;
fn get(self, src: &KafkaBatchContext) -> &KafkaSeeker {
src.seeker()
}
}
}