slbotbm commented on code in PR #3610:
URL: https://github.com/apache/iggy/pull/3610#discussion_r3600730300
##########
foreign/cpp/src/type_conversion.rs:
##########
@@ -314,12 +433,36 @@ impl From<RustConsumerGroupDetails> for
ffi::ConsumerGroupDetails {
}
}
-impl From<RustIggyMessage> for ffi::IggyMessagePolled {
- fn from(message: RustIggyMessage) -> Self {
+impl TryFrom<RustIggyMessage> for ffi::IggyMessagePolled {
+ type Error = String;
+
+ fn try_from(message: RustIggyMessage) -> Result<Self, Self::Error> {
let id_bytes = message.header.id.to_le_bytes();
let id_lo = u64::from_le_bytes(id_bytes[0..8].try_into().unwrap());
let id_hi = u64::from_le_bytes(id_bytes[8..16].try_into().unwrap());
- ffi::IggyMessagePolled {
+ let user_headers = match message.user_headers {
+ Some(raw_headers) => {
+ let wire_headers =
WireUserHeaders::from_bytes(raw_headers).map_err(|error| {
Review Comment:
I changed the code to emit empty headers for malformed user-headers TLV
while preserving the message and the batch, though I cannot issue a warning
from the rust side to the cpp side without introducing some field like
`user_header_warning` that will get populated on errors. Though this is a
pretty awkward design.
##########
foreign/cpp/src/lib.rs:
##########
@@ -88,11 +88,40 @@ mod ffi {
topics_count: u32,
}
+ #[repr(u8)]
+ enum HeaderKind {
+ Raw = 1,
+ String = 2,
+ Bool = 3,
+ Int8 = 4,
+ Int16 = 5,
+ Int32 = 6,
+ Int64 = 7,
+ Int128 = 8,
+ UInt8 = 9,
Review Comment:
Done
##########
foreign/cpp/src/type_conversion.rs:
##########
@@ -188,6 +194,119 @@ impl From<RustStats> for ffi::Stats {
}
}
+impl From<RustTransportEndpoints> for ffi::TransportEndpoints {
+ fn from(endpoints: RustTransportEndpoints) -> Self {
+ ffi::TransportEndpoints {
+ tcp: endpoints.tcp,
+ quic: endpoints.quic,
+ http: endpoints.http,
+ websocket: endpoints.websocket,
+ }
+ }
+}
+
+impl From<RustClusterNode> for ffi::ClusterNode {
+ fn from(node: RustClusterNode) -> Self {
+ ffi::ClusterNode {
+ name: node.name,
+ ip: node.ip,
+ endpoints: ffi::TransportEndpoints::from(node.endpoints),
+ role: node.role.to_string(),
+ status: node.status.to_string(),
+ }
+ }
+}
+
+impl From<RustClusterMetadata> for ffi::ClusterMetadata {
+ fn from(metadata: RustClusterMetadata) -> Self {
+ ffi::ClusterMetadata {
+ name: metadata.name,
+ nodes: metadata
+ .nodes
+ .into_iter()
+ .map(ffi::ClusterNode::from)
+ .collect(),
+ }
+ }
+}
+
+impl From<ffi::GlobalPermissions> for RustGlobalPermissions {
+ fn from(permissions: ffi::GlobalPermissions) -> Self {
+ RustGlobalPermissions {
+ manage_servers: permissions.manage_servers,
+ read_servers: permissions.read_servers,
+ manage_users: permissions.manage_users,
+ read_users: permissions.read_users,
+ manage_streams: permissions.manage_streams,
+ read_streams: permissions.read_streams,
+ manage_topics: permissions.manage_topics,
+ read_topics: permissions.read_topics,
+ poll_messages: permissions.poll_messages,
+ send_messages: permissions.send_messages,
+ }
+ }
+}
+
+impl From<ffi::TopicPermissions> for RustTopicPermissions {
+ fn from(permissions: ffi::TopicPermissions) -> Self {
+ RustTopicPermissions {
+ manage_topic: permissions.manage_topic,
+ read_topic: permissions.read_topic,
+ poll_messages: permissions.poll_messages,
+ send_messages: permissions.send_messages,
+ }
+ }
+}
+
+impl TryFrom<ffi::StreamPermissions> for RustStreamPermissions {
+ type Error = String;
+
+ fn try_from(permissions: ffi::StreamPermissions) -> Result<Self,
Self::Error> {
+ let mut topics = BTreeMap::new();
+ for entry in permissions.topics {
+ let topic_id = entry.topic_id as usize;
+ if topics
+ .insert(topic_id,
RustTopicPermissions::from(entry.permissions))
+ .is_some()
+ {
+ return Err(format!("duplicate topic permission ID:
{topic_id}"));
+ }
+ }
+ let topics = (!topics.is_empty()).then_some(topics);
+
+ Ok(RustStreamPermissions {
+ manage_stream: permissions.manage_stream,
+ read_stream: permissions.read_stream,
+ manage_topics: permissions.manage_topics,
+ read_topics: permissions.read_topics,
+ poll_messages: permissions.poll_messages,
+ send_messages: permissions.send_messages,
+ topics,
+ })
+ }
+}
+
+impl TryFrom<ffi::Permissions> for RustPermissions {
Review Comment:
This will be difficult to do -- the current tests only test the final cpp
library, and there is no wiring in bazel or in the CI to actually run rust
tests. We'll need to explicitly call cargo to run the tests from bazel to do
this
##########
foreign/cpp/src/type_conversion.rs:
##########
@@ -314,12 +433,36 @@ impl From<RustConsumerGroupDetails> for
ffi::ConsumerGroupDetails {
}
}
-impl From<RustIggyMessage> for ffi::IggyMessagePolled {
- fn from(message: RustIggyMessage) -> Self {
+impl TryFrom<RustIggyMessage> for ffi::IggyMessagePolled {
+ type Error = String;
+
+ fn try_from(message: RustIggyMessage) -> Result<Self, Self::Error> {
let id_bytes = message.header.id.to_le_bytes();
let id_lo = u64::from_le_bytes(id_bytes[0..8].try_into().unwrap());
let id_hi = u64::from_le_bytes(id_bytes[8..16].try_into().unwrap());
- ffi::IggyMessagePolled {
+ let user_headers = match message.user_headers {
Review Comment:
added comment
##########
foreign/cpp/src/type_conversion.rs:
##########
@@ -330,45 +473,352 @@ impl From<RustIggyMessage> for ffi::IggyMessagePolled {
payload_length: message.header.payload_length,
reserved: message.header.reserved,
payload: message.payload.to_vec(),
- user_headers: message
- .user_headers
- .map(|headers| headers.to_vec())
- .unwrap_or_default(),
+ user_headers,
+ })
+ }
+}
+
+impl From<RustHeaderEntry> for ffi::HeaderEntry {
+ fn from(entry: RustHeaderEntry) -> Self {
+ ffi::HeaderEntry {
+ key: ffi::HeaderField {
+ kind: entry.key.kind().as_code(),
+ value: entry.key.as_bytes().to_vec(),
+ },
+ value: ffi::HeaderField {
+ kind: entry.value.kind().as_code(),
+ value: entry.value.as_bytes().to_vec(),
+ },
}
}
}
+impl TryFrom<ffi::HeaderEntry> for RustHeaderEntry {
Review Comment:
done
##########
foreign/cpp/src/type_conversion.rs:
##########
@@ -330,45 +473,352 @@ impl From<RustIggyMessage> for ffi::IggyMessagePolled {
payload_length: message.header.payload_length,
reserved: message.header.reserved,
payload: message.payload.to_vec(),
- user_headers: message
- .user_headers
- .map(|headers| headers.to_vec())
- .unwrap_or_default(),
+ user_headers,
+ })
+ }
+}
+
+impl From<RustHeaderEntry> for ffi::HeaderEntry {
Review Comment:
done
##########
foreign/cpp/src/type_conversion.rs:
##########
@@ -330,45 +473,352 @@ impl From<RustIggyMessage> for ffi::IggyMessagePolled {
payload_length: message.header.payload_length,
reserved: message.header.reserved,
payload: message.payload.to_vec(),
- user_headers: message
- .user_headers
- .map(|headers| headers.to_vec())
- .unwrap_or_default(),
+ user_headers,
+ })
+ }
+}
+
+impl From<RustHeaderEntry> for ffi::HeaderEntry {
+ fn from(entry: RustHeaderEntry) -> Self {
+ ffi::HeaderEntry {
+ key: ffi::HeaderField {
+ kind: entry.key.kind().as_code(),
+ value: entry.key.as_bytes().to_vec(),
+ },
+ value: ffi::HeaderField {
+ kind: entry.value.kind().as_code(),
+ value: entry.value.as_bytes().to_vec(),
+ },
}
}
}
+impl TryFrom<ffi::HeaderEntry> for RustHeaderEntry {
+ type Error = String;
+
+ fn try_from(entry: ffi::HeaderEntry) -> Result<Self, Self::Error> {
+ Ok(RustHeaderEntry {
+ key: {
+ let kind = RustHeaderKind::from_code(entry.key.kind)
+ .map_err(|error| format!("Could not convert header field:
{error}"))?;
+
+ match kind {
+ RustHeaderKind::Raw =>
RustHeaderKey::try_from(entry.key.value)
+ .map_err(|error| format!("Could not convert header
field: {error}"))?,
+ RustHeaderKind::String => {
+ let value =
String::from_utf8(entry.key.value).map_err(|_| {
+ "Could not convert header field: invalid UTF-8
string".to_string()
+ })?;
+ RustHeaderKey::try_from(value)
+ .map_err(|error| format!("Could not convert header
field: {error}"))?
+ }
+ RustHeaderKind::Bool => match entry.key.value.as_slice() {
+ [0] => RustHeaderKey::from(false),
+ [1] => RustHeaderKey::from(true),
+ _ => {
+ return Err(
+ "Could not convert header field: bool values
must encode as 0 or 1"
+ .to_string(),
+ );
+ }
+ },
+ RustHeaderKind::Int8 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(i8::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int8 values
require exactly 1 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int16 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(i16::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int16 values
require exactly 2 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int32 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(i32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int32 values
require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int64 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(i64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int64 values
require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int128 => match entry.key.value.try_into()
{
+ Ok(bytes) =>
RustHeaderKey::from(i128::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int128 values
require exactly 16 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint8 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(u8::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint8 values
require exactly 1 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint16 => match entry.key.value.try_into()
{
+ Ok(bytes) =>
RustHeaderKey::from(u16::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint16 values
require exactly 2 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint32 => match entry.key.value.try_into()
{
+ Ok(bytes) =>
RustHeaderKey::from(u32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint32 values
require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint64 => match entry.key.value.try_into()
{
+ Ok(bytes) =>
RustHeaderKey::from(u64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint64 values
require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint128 => match
entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(u128::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint128
values require exactly 16 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Float32 => match
entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(f32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: float32
values require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Float64 => match
entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(f64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: float64
values require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ }
+ },
+ value: {
+ let kind = RustHeaderKind::from_code(entry.value.kind)
+ .map_err(|error| format!("Could not convert header field:
{error}"))?;
+
+ match kind {
+ RustHeaderKind::Raw =>
RustHeaderValue::try_from(entry.value.value)
+ .map_err(|error| format!("Could not convert header
field: {error}"))?,
+ RustHeaderKind::String => {
+ let value =
String::from_utf8(entry.value.value).map_err(|_| {
+ "Could not convert header field: invalid UTF-8
string".to_string()
+ })?;
+ RustHeaderValue::try_from(value)
+ .map_err(|error| format!("Could not convert header
field: {error}"))?
+ }
+ RustHeaderKind::Bool => match entry.value.value.as_slice()
{
+ [0] => RustHeaderValue::from(false),
+ [1] => RustHeaderValue::from(true),
+ _ => {
+ return Err(
+ "Could not convert header field: bool values
must encode as 0 or 1"
+ .to_string(),
+ );
+ }
+ },
+ RustHeaderKind::Int8 => match entry.value.value.try_into()
{
+ Ok(bytes) =>
RustHeaderValue::from(i8::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int8 values
require exactly 1 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int16 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(i16::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int16 values
require exactly 2 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int32 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(i32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int32 values
require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int64 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(i64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int64 values
require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int128 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(i128::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int128 values
require exactly 16 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint8 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u8::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint8 values
require exactly 1 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint16 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u16::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint16 values
require exactly 2 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint32 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint32 values
require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint64 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint64 values
require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint128 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u128::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint128
values require exactly 16 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Float32 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(f32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: float32
values require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Float64 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(f64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: float64
values require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ }
+ },
+ })
+ }
+}
+
impl TryFrom<ffi::IggyMessageToSend> for RustIggyMessage {
type Error = String;
fn try_from(message: ffi::IggyMessageToSend) -> Result<Self, Self::Error> {
- if !message.user_headers.is_empty() {
- return Err(
- "Could not convert message: user_headers are not yet supported
in the C++ SDK"
- .to_string(),
- );
+ let mut user_headers = BTreeMap::new();
+ for entry in message.user_headers {
+ let header_entry = RustHeaderEntry::try_from(entry)
+ .map_err(|error| format!("Could not convert message user
headers: {error}"))?;
+ if user_headers
+ .insert(header_entry.key, header_entry.value)
+ .is_some()
+ {
+ return Err(
+ "Could not convert message user headers: duplicate header
key".to_string(),
+ );
+ }
}
let id = ((message.id_hi as u128) << 64) | (message.id_lo as u128);
let payload = Bytes::from(message.payload);
- RustIggyMessage::builder()
- .id(id)
- .payload(payload)
- .build()
- .map_err(|error| format!("Could not convert message: {error}"))
+ if user_headers.is_empty() {
Review Comment:
done
##########
foreign/cpp/src/type_conversion.rs:
##########
@@ -330,45 +473,352 @@ impl From<RustIggyMessage> for ffi::IggyMessagePolled {
payload_length: message.header.payload_length,
reserved: message.header.reserved,
payload: message.payload.to_vec(),
- user_headers: message
- .user_headers
- .map(|headers| headers.to_vec())
- .unwrap_or_default(),
+ user_headers,
+ })
+ }
+}
+
+impl From<RustHeaderEntry> for ffi::HeaderEntry {
+ fn from(entry: RustHeaderEntry) -> Self {
+ ffi::HeaderEntry {
+ key: ffi::HeaderField {
+ kind: entry.key.kind().as_code(),
+ value: entry.key.as_bytes().to_vec(),
+ },
+ value: ffi::HeaderField {
+ kind: entry.value.kind().as_code(),
+ value: entry.value.as_bytes().to_vec(),
+ },
}
}
}
+impl TryFrom<ffi::HeaderEntry> for RustHeaderEntry {
+ type Error = String;
+
+ fn try_from(entry: ffi::HeaderEntry) -> Result<Self, Self::Error> {
+ Ok(RustHeaderEntry {
+ key: {
+ let kind = RustHeaderKind::from_code(entry.key.kind)
+ .map_err(|error| format!("Could not convert header field:
{error}"))?;
+
+ match kind {
+ RustHeaderKind::Raw =>
RustHeaderKey::try_from(entry.key.value)
+ .map_err(|error| format!("Could not convert header
field: {error}"))?,
+ RustHeaderKind::String => {
+ let value =
String::from_utf8(entry.key.value).map_err(|_| {
+ "Could not convert header field: invalid UTF-8
string".to_string()
+ })?;
+ RustHeaderKey::try_from(value)
+ .map_err(|error| format!("Could not convert header
field: {error}"))?
+ }
+ RustHeaderKind::Bool => match entry.key.value.as_slice() {
+ [0] => RustHeaderKey::from(false),
+ [1] => RustHeaderKey::from(true),
+ _ => {
+ return Err(
+ "Could not convert header field: bool values
must encode as 0 or 1"
+ .to_string(),
+ );
+ }
+ },
+ RustHeaderKind::Int8 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(i8::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int8 values
require exactly 1 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int16 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(i16::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int16 values
require exactly 2 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int32 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(i32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int32 values
require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int64 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(i64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int64 values
require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int128 => match entry.key.value.try_into()
{
+ Ok(bytes) =>
RustHeaderKey::from(i128::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int128 values
require exactly 16 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint8 => match entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(u8::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint8 values
require exactly 1 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint16 => match entry.key.value.try_into()
{
+ Ok(bytes) =>
RustHeaderKey::from(u16::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint16 values
require exactly 2 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint32 => match entry.key.value.try_into()
{
+ Ok(bytes) =>
RustHeaderKey::from(u32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint32 values
require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint64 => match entry.key.value.try_into()
{
+ Ok(bytes) =>
RustHeaderKey::from(u64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint64 values
require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint128 => match
entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(u128::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint128
values require exactly 16 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Float32 => match
entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(f32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: float32
values require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Float64 => match
entry.key.value.try_into() {
+ Ok(bytes) =>
RustHeaderKey::from(f64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: float64
values require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ }
+ },
+ value: {
+ let kind = RustHeaderKind::from_code(entry.value.kind)
+ .map_err(|error| format!("Could not convert header field:
{error}"))?;
+
+ match kind {
+ RustHeaderKind::Raw =>
RustHeaderValue::try_from(entry.value.value)
+ .map_err(|error| format!("Could not convert header
field: {error}"))?,
+ RustHeaderKind::String => {
+ let value =
String::from_utf8(entry.value.value).map_err(|_| {
+ "Could not convert header field: invalid UTF-8
string".to_string()
+ })?;
+ RustHeaderValue::try_from(value)
+ .map_err(|error| format!("Could not convert header
field: {error}"))?
+ }
+ RustHeaderKind::Bool => match entry.value.value.as_slice()
{
+ [0] => RustHeaderValue::from(false),
+ [1] => RustHeaderValue::from(true),
+ _ => {
+ return Err(
+ "Could not convert header field: bool values
must encode as 0 or 1"
+ .to_string(),
+ );
+ }
+ },
+ RustHeaderKind::Int8 => match entry.value.value.try_into()
{
+ Ok(bytes) =>
RustHeaderValue::from(i8::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int8 values
require exactly 1 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int16 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(i16::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int16 values
require exactly 2 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int32 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(i32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int32 values
require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int64 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(i64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int64 values
require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Int128 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(i128::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: int128 values
require exactly 16 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint8 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u8::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint8 values
require exactly 1 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint16 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u16::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint16 values
require exactly 2 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint32 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint32 values
require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint64 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint64 values
require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Uint128 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(u128::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: uint128
values require exactly 16 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Float32 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(f32::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: float32
values require exactly 4 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ RustHeaderKind::Float64 => match
entry.value.value.try_into() {
+ Ok(bytes) =>
RustHeaderValue::from(f64::from_le_bytes(bytes)),
+ Err(value) => {
+ return Err(format!(
+ "Could not convert header field: float64
values require exactly 8 bytes, got {}",
+ value.len()
+ ));
+ }
+ },
+ }
+ },
+ })
+ }
+}
+
impl TryFrom<ffi::IggyMessageToSend> for RustIggyMessage {
type Error = String;
fn try_from(message: ffi::IggyMessageToSend) -> Result<Self, Self::Error> {
- if !message.user_headers.is_empty() {
- return Err(
- "Could not convert message: user_headers are not yet supported
in the C++ SDK"
- .to_string(),
- );
+ let mut user_headers = BTreeMap::new();
Review Comment:
added todo to mention this in high level sdk doc
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]