This is an automated email from the ASF dual-hosted git repository.
piotr pushed a commit to branch non_string_header_key
in repository https://gitbox.apache.org/repos/asf/iggy.git
The following commit(s) were added to refs/heads/non_string_header_key by this
push:
new b6d590482 Refactor user headers to be idimomatic
b6d590482 is described below
commit b6d590482cda54d0a68fe7e62a8c1e9aa704748a
Author: spetz <[email protected]>
AuthorDate: Thu Jan 29 20:22:02 2026 +0100
Refactor user headers to be idimomatic
---
core/cli/src/args/message.rs | 61 +-
core/common/src/types/message/iggy_message.rs | 22 +-
core/common/src/types/message/user_headers.rs | 1273 ++++++++++++--------
.../tests/cli/message/test_message_poll_command.rs | 5 +-
.../tests/cli/message/test_message_send_command.rs | 13 +-
.../server/scenarios/create_message_payload.rs | 21 +-
.../tests/server/scenarios/encryption_scenario.rs | 54 +-
.../server/scenarios/message_headers_scenario.rs | 21 +-
.../server/scenarios/message_size_scenario.rs | 5 +-
.../tests/server/scenarios/offset_scenario.rs | 15 +-
.../tests/server/scenarios/timestamp_scenario.rs | 15 +-
core/sdk/src/prelude.rs | 12 +-
core/server/server.http | 26 +-
core/tools/src/data-seeder/seeder.rs | 15 +-
.../message-headers/message-type/consumer/main.rs | 2 +-
.../message-headers/message-type/producer/main.rs | 5 +-
.../message-headers/typed-headers/producer/main.rs | 26 +-
examples/rust/src/shared/codec.rs | 4 +-
.../Iggy_SDK/JsonConverters/MessageConverter.cs | 4 +-
19 files changed, 922 insertions(+), 677 deletions(-)
diff --git a/core/cli/src/args/message.rs b/core/cli/src/args/message.rs
index da5e742e6..5157722fe 100644
--- a/core/cli/src/args/message.rs
+++ b/core/cli/src/args/message.rs
@@ -128,7 +128,66 @@ fn parse_key_val(s: &str) -> Result<(HeaderKey,
HeaderValue), IggyError> {
}
let key = HeaderKey::from_str(parts[0])?;
- let value = HeaderValue::from_kind_str_and_value_str(parts[1], parts[2])?;
+ let kind = HeaderKind::from_str(parts[1])?;
+ let value_str = parts[2];
+
+ let value = match kind {
+ HeaderKind::Raw => HeaderValue::try_from(value_str.as_bytes())?,
+ HeaderKind::String => HeaderValue::try_from(value_str)?,
+ HeaderKind::Bool => value_str
+ .parse::<bool>()
+ .map_err(|_| IggyError::InvalidBooleanValue)?
+ .into(),
+ HeaderKind::Int8 => value_str
+ .parse::<i8>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Int16 => value_str
+ .parse::<i16>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Int32 => value_str
+ .parse::<i32>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Int64 => value_str
+ .parse::<i64>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Int128 => value_str
+ .parse::<i128>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Uint8 => value_str
+ .parse::<u8>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Uint16 => value_str
+ .parse::<u16>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Uint32 => value_str
+ .parse::<u32>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Uint64 => value_str
+ .parse::<u64>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Uint128 => value_str
+ .parse::<u128>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Float32 => value_str
+ .parse::<f32>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ HeaderKind::Float64 => value_str
+ .parse::<f64>()
+ .map_err(|_| IggyError::InvalidNumberValue)?
+ .into(),
+ };
+
Ok((key, value))
}
diff --git a/core/common/src/types/message/iggy_message.rs
b/core/common/src/types/message/iggy_message.rs
index 5bc464fc1..f34b2b272 100644
--- a/core/common/src/types/message/iggy_message.rs
+++ b/core/common/src/types/message/iggy_message.rs
@@ -680,8 +680,8 @@ mod tests {
fn test_create_with_headers() {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("content-type").unwrap(),
- HeaderValue::from_str("text/plain").unwrap(),
+ HeaderKey::try_from("content-type").unwrap(),
+ HeaderValue::try_from("text/plain").unwrap(),
);
let message = IggyMessage::builder()
@@ -694,7 +694,7 @@ mod tests {
let headers_map = message.user_headers_map().unwrap().unwrap();
assert_eq!(headers_map.len(), 1);
-
assert!(headers_map.contains_key(&HeaderKey::from_string("content-type").unwrap()));
+
assert!(headers_map.contains_key(&HeaderKey::try_from("content-type").unwrap()));
}
#[test]
@@ -736,12 +736,12 @@ mod tests {
fn test_json_serialization_with_headers() {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("content-type").unwrap(),
- HeaderValue::from_str("text/plain").unwrap(),
+ HeaderKey::try_from("content-type").unwrap(),
+ HeaderValue::try_from("text/plain").unwrap(),
);
headers.insert(
- HeaderKey::from_string("correlation-id").unwrap(),
- HeaderValue::from_str("123456").unwrap(),
+ HeaderKey::try_from("correlation-id").unwrap(),
+ HeaderValue::try_from("123456").unwrap(),
);
let original = IggyMessage::builder()
@@ -785,12 +785,12 @@ mod tests {
assert_eq!(original_map.len(), deserialized_map.len());
assert_eq!(
- original_map.get(&HeaderKey::from_string("content-type").unwrap()),
-
deserialized_map.get(&HeaderKey::from_string("content-type").unwrap())
+ original_map.get(&HeaderKey::try_from("content-type").unwrap()),
+ deserialized_map.get(&HeaderKey::try_from("content-type").unwrap())
);
assert_eq!(
-
original_map.get(&HeaderKey::from_string("correlation-id").unwrap()),
-
deserialized_map.get(&HeaderKey::from_string("correlation-id").unwrap())
+ original_map.get(&HeaderKey::try_from("correlation-id").unwrap()),
+
deserialized_map.get(&HeaderKey::try_from("correlation-id").unwrap())
);
}
}
diff --git a/core/common/src/types/message/user_headers.rs
b/core/common/src/types/message/user_headers.rs
index 3912fd88f..6efaf1054 100644
--- a/core/common/src/types/message/user_headers.rs
+++ b/core/common/src/types/message/user_headers.rs
@@ -28,8 +28,63 @@ use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::str::FromStr;
+/// Type alias for header keys in user-defined message headers.
+///
+/// Header keys can be created from various types using `From`/`TryFrom`
traits:
+/// - Fixed-size types (infallible): `bool`, `i8`-`i128`, `u8`-`u128`, `f32`,
`f64`
+/// - Variable-size types (fallible, max 255 bytes): `&str`, `String`,
`&[u8]`, `Vec<u8>`
+///
+/// Values can be extracted back using `TryFrom` or `as_*` methods.
+///
+/// # Examples
+///
+/// ```
+/// use iggy_common::{HeaderKey, HeaderValue, IggyError};
+///
+/// // Create from string (most common)
+/// let key = HeaderKey::try_from("content-type")?;
+///
+/// // Create from integer (for numeric keys)
+/// let key: HeaderKey = 42u32.into();
+///
+/// // Extract value back
+/// let num: u32 = key.try_into()?;
+/// assert_eq!(num, 42);
+/// # Ok::<(), IggyError>(())
+/// ```
pub type HeaderKey = HeaderField<KeyMarker>;
+
+/// Type alias for header values in user-defined message headers.
+///
+/// Header values can be created from various types using `From`/`TryFrom`
traits:
+/// - Fixed-size types (infallible): `bool`, `i8`-`i128`, `u8`-`u128`, `f32`,
`f64`
+/// - Variable-size types (fallible, max 255 bytes): `&str`, `String`,
`&[u8]`, `Vec<u8>`
+///
+/// Values can be extracted back using `TryFrom` or `as_*` methods.
+///
+/// # Examples
+///
+/// ```
+/// use iggy_common::{HeaderKey, HeaderValue, IggyError};
+///
+/// // Create from various types
+/// let str_val = HeaderValue::try_from("text/plain")?;
+/// let int_val: HeaderValue = 42i32.into();
+/// let bool_val: HeaderValue = true.into();
+/// let float_val: HeaderValue = 3.14f64.into();
+///
+/// // Extract values back using TryFrom
+/// let num: i32 = int_val.try_into()?;
+/// assert_eq!(num, 42);
+///
+/// // Or use as_* methods
+/// let str_val = HeaderValue::try_from("hello")?;
+/// assert_eq!(str_val.as_str()?, "hello");
+/// # Ok::<(), IggyError>(())
+/// ```
pub type HeaderValue = HeaderField<ValueMarker>;
+
+/// Type alias for a collection of user-defined message headers.
pub type UserHeaders = HashMap<HeaderKey, HeaderValue>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -38,33 +93,124 @@ pub struct KeyMarker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ValueMarker;
+/// A typed header field that can be used as either a key or value in message
headers.
+///
+/// `HeaderField` is a generic struct parameterized by a marker type
(`KeyMarker` or `ValueMarker`)
+/// to distinguish between keys and values at the type level. Use the type
aliases
+/// [`HeaderKey`] and [`HeaderValue`] instead of using this struct directly.
+///
+/// # Creating Header Fields
+///
+/// Use `From` trait for fixed-size types (infallible):
+/// ```
+/// use iggy_common::HeaderValue;
+///
+/// let val: HeaderValue = 42i32.into();
+/// let val: HeaderValue = true.into();
+/// let val: HeaderValue = 3.14f64.into();
+/// ```
+///
+/// Use `TryFrom` trait for variable-size types (fallible, max 255 bytes):
+/// ```
+/// use iggy_common::{HeaderValue, IggyError};
+///
+/// let val = HeaderValue::try_from("hello")?;
+/// let val = HeaderValue::try_from(vec![1u8, 2, 3])?;
+/// # Ok::<(), IggyError>(())
+/// ```
+///
+/// # Extracting Values
+///
+/// Use `TryFrom` to extract values (returns error if kind doesn't match):
+/// ```
+/// use iggy_common::{HeaderValue, IggyError};
+///
+/// let val: HeaderValue = 42i32.into();
+/// let num: i32 = val.try_into()?;
+///
+/// // Using reference to avoid consuming the value
+/// let val: HeaderValue = 100u64.into();
+/// let num: u64 = (&val).try_into()?;
+/// // val is still usable here
+/// # Ok::<(), IggyError>(())
+/// ```
+///
+/// Or use `as_*` methods:
+/// ```
+/// use iggy_common::{HeaderValue, IggyError};
+///
+/// let val: HeaderValue = 42i32.into();
+/// assert_eq!(val.as_int32()?, 42);
+/// # Ok::<(), IggyError>(())
+/// ```
#[serde_as]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct HeaderField<T> {
+ /// The type of value stored in this header field.
pub kind: HeaderKind,
+ /// The raw bytes of the value, encoded according to `kind`.
#[serde_as(as = "Base64")]
pub value: Bytes,
#[serde(skip)]
_marker: PhantomData<T>,
}
+/// Indicates the type of value stored in a [`HeaderField`].
+///
+/// This enum is used to track what type of data is stored in the header's raw
bytes,
+/// enabling proper deserialization and type checking when extracting values.
+///
+/// # Supported Types
+///
+/// | Kind | Rust Type | Size (bytes) |
+/// |------|-----------|--------------|
+/// | `Raw` | `&[u8]` / `Vec<u8>` | 1-255 |
+/// | `String` | `&str` / `String` | 1-255 |
+/// | `Bool` | `bool` | 1 |
+/// | `Int8` | `i8` | 1 |
+/// | `Int16` | `i16` | 2 |
+/// | `Int32` | `i32` | 4 |
+/// | `Int64` | `i64` | 8 |
+/// | `Int128` | `i128` | 16 |
+/// | `Uint8` | `u8` | 1 |
+/// | `Uint16` | `u16` | 2 |
+/// | `Uint32` | `u32` | 4 |
+/// | `Uint64` | `u64` | 8 |
+/// | `Uint128` | `u128` | 16 |
+/// | `Float32` | `f32` | 4 |
+/// | `Float64` | `f64` | 8 |
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum HeaderKind {
+ /// Raw binary data.
Raw,
+ /// UTF-8 encoded string.
String,
+ /// Boolean value.
Bool,
+ /// Signed 8-bit integer.
Int8,
+ /// Signed 16-bit integer.
Int16,
+ /// Signed 32-bit integer.
Int32,
+ /// Signed 64-bit integer.
Int64,
+ /// Signed 128-bit integer.
Int128,
+ /// Unsigned 8-bit integer.
Uint8,
+ /// Unsigned 16-bit integer.
Uint16,
+ /// Unsigned 32-bit integer.
Uint32,
+ /// Unsigned 64-bit integer.
Uint64,
+ /// Unsigned 128-bit integer.
Uint128,
+ /// 32-bit floating point number.
Float32,
+ /// 64-bit floating point number.
Float64,
}
@@ -174,73 +320,11 @@ impl<T> Hash for HeaderField<T> {
impl<T> FromStr for HeaderField<T> {
type Err = IggyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
- Self::from_string(s)
- }
-}
-
-impl<T> TryFrom<&str> for HeaderField<T> {
- type Error = IggyError;
- fn try_from(value: &str) -> Result<Self, Self::Error> {
- Self::from_string(value)
+ Self::try_from(s)
}
}
impl<T> HeaderField<T> {
- pub fn from_kind_str_and_value_str(kind: &str, value: &str) ->
Result<Self, IggyError> {
- let kind = HeaderKind::from_str(kind)?;
- Self::from_kind_and_value_str(kind, value)
- }
-
- pub fn from_kind_and_value_str(kind: HeaderKind, value: &str) ->
Result<Self, IggyError> {
- match kind {
- HeaderKind::Raw => Self::from_raw(value.as_bytes()),
- HeaderKind::String => Self::from_string(value),
- HeaderKind::Bool => {
- Self::from_bool(value.parse().map_err(|_|
IggyError::InvalidBooleanValue)?)
- }
- HeaderKind::Int8 => {
- Self::from_int8(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Int16 => {
- Self::from_int16(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Int32 => {
- Self::from_int32(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Int64 => {
- Self::from_int64(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Int128 => {
- Self::from_int128(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Uint8 => {
- Self::from_uint8(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Uint16 => {
- Self::from_uint16(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Uint32 => {
- Self::from_uint32(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Uint64 => {
- Self::from_uint64(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Uint128 => {
- Self::from_uint128(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Float32 => {
- Self::from_float32(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- HeaderKind::Float64 => {
- Self::from_float64(value.parse().map_err(|_|
IggyError::InvalidNumberValue)?)
- }
- }
- }
-
- pub fn from_raw(value: &[u8]) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Raw, value)
- }
-
pub fn as_raw(&self) -> Result<&[u8], IggyError> {
if self.kind != HeaderKind::Raw {
return Err(IggyError::InvalidHeaderValue);
@@ -248,10 +332,6 @@ impl<T> HeaderField<T> {
Ok(&self.value)
}
- pub fn from_string(value: &str) -> Result<Self, IggyError> {
- Self::from(HeaderKind::String, value.as_bytes())
- }
-
pub fn as_str(&self) -> Result<&str, IggyError> {
if self.kind != HeaderKind::String {
return Err(IggyError::InvalidHeaderValue);
@@ -259,10 +339,6 @@ impl<T> HeaderField<T> {
std::str::from_utf8(&self.value).map_err(|_| IggyError::InvalidUtf8)
}
- pub fn from_bool(value: bool) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Bool, if value { &[1] } else { &[0] })
- }
-
pub fn as_bool(&self) -> Result<bool, IggyError> {
if self.kind != HeaderKind::Bool {
return Err(IggyError::InvalidHeaderValue);
@@ -274,83 +350,59 @@ impl<T> HeaderField<T> {
}
}
- pub fn from_int8(value: i8) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Int8, &value.to_le_bytes())
- }
-
pub fn as_int8(&self) -> Result<i8, IggyError> {
if self.kind != HeaderKind::Int8 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(i8::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_int16(value: i16) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Int16, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(i8::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_int16(&self) -> Result<i16, IggyError> {
if self.kind != HeaderKind::Int16 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(i16::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_int32(value: i32) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Int32, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(i16::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_int32(&self) -> Result<i32, IggyError> {
if self.kind != HeaderKind::Int32 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(i32::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_int64(value: i64) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Int64, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(i32::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_int64(&self) -> Result<i64, IggyError> {
if self.kind != HeaderKind::Int64 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(i64::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_int128(value: i128) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Int128, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(i64::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_int128(&self) -> Result<i128, IggyError> {
if self.kind != HeaderKind::Int128 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(i128::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_uint8(value: u8) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Uint8, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(i128::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_uint8(&self) -> Result<u8, IggyError> {
@@ -360,94 +412,70 @@ impl<T> HeaderField<T> {
Ok(self.value[0])
}
- pub fn from_uint16(value: u16) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Uint16, &value.to_le_bytes())
- }
-
pub fn as_uint16(&self) -> Result<u16, IggyError> {
if self.kind != HeaderKind::Uint16 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(u16::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_uint32(value: u32) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Uint32, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(u16::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_uint32(&self) -> Result<u32, IggyError> {
if self.kind != HeaderKind::Uint32 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(u32::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_uint64(value: u64) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Uint64, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(u32::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_uint64(&self) -> Result<u64, IggyError> {
if self.kind != HeaderKind::Uint64 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(u64::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_uint128(value: u128) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Uint128, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(u64::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_uint128(&self) -> Result<u128, IggyError> {
if self.kind != HeaderKind::Uint128 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(u128::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_float32(value: f32) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Float32, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(u128::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_float32(&self) -> Result<f32, IggyError> {
if self.kind != HeaderKind::Float32 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(f32::from_le_bytes(value.unwrap()))
- }
-
- pub fn from_float64(value: f64) -> Result<Self, IggyError> {
- Self::from(HeaderKind::Float64, &value.to_le_bytes())
+ self.value
+ .as_ref()
+ .try_into()
+ .map(f32::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn as_float64(&self) -> Result<f64, IggyError> {
if self.kind != HeaderKind::Float64 {
return Err(IggyError::InvalidHeaderValue);
}
- let value = self.value.to_vec().try_into();
- if value.is_err() {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(f64::from_le_bytes(value.unwrap()))
+ self.value
+ .as_ref()
+ .try_into()
+ .map(f64::from_le_bytes)
+ .map_err(|_| IggyError::InvalidHeaderValue)
}
pub fn to_string_value(&self) -> String {
@@ -457,64 +485,383 @@ impl<T> HeaderField<T> {
HeaderKind::Bool => format!("{}", self.value[0] != 0),
HeaderKind::Int8 => format!(
"{}",
- i8::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ i8::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Int16 => format!(
"{}",
- i16::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ i16::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Int32 => format!(
"{}",
- i32::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ i32::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Int64 => format!(
"{}",
- i64::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ i64::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Int128 => format!(
"{}",
- i128::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ i128::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Uint8 => format!(
"{}",
- u8::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ u8::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Uint16 => format!(
"{}",
- u16::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ u16::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Uint32 => format!(
"{}",
- u32::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ u32::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Uint64 => format!(
"{}",
- u64::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ u64::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Uint128 => format!(
"{}",
- u128::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ u128::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Float32 => format!(
"{}",
- f32::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ f32::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
HeaderKind::Float64 => format!(
"{}",
- f64::from_le_bytes(self.value.to_vec().try_into().unwrap())
+ f64::from_le_bytes(self.value.as_ref().try_into().unwrap())
),
}
}
- fn from(kind: HeaderKind, value: &[u8]) -> Result<Self, IggyError> {
- if value.is_empty() || value.len() > 255 {
- return Err(IggyError::InvalidHeaderValue);
- }
- Ok(Self {
+ fn new_unchecked(kind: HeaderKind, value: &[u8]) -> Self {
+ Self {
kind,
value: Bytes::from(value.to_vec()),
_marker: PhantomData,
- })
+ }
+ }
+}
+
+impl<T> TryFrom<&str> for HeaderField<T> {
+ type Error = IggyError;
+ fn try_from(value: &str) -> Result<Self, Self::Error> {
+ if value.is_empty() || value.len() > 255 {
+ return Err(IggyError::InvalidHeaderValue);
+ }
+ Ok(Self::new_unchecked(HeaderKind::String, value.as_bytes()))
+ }
+}
+
+impl<T> TryFrom<String> for HeaderField<T> {
+ type Error = IggyError;
+ fn try_from(value: String) -> Result<Self, Self::Error> {
+ Self::try_from(value.as_str())
+ }
+}
+
+impl<T> TryFrom<&[u8]> for HeaderField<T> {
+ type Error = IggyError;
+ fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
+ if value.is_empty() || value.len() > 255 {
+ return Err(IggyError::InvalidHeaderValue);
+ }
+ Ok(Self::new_unchecked(HeaderKind::Raw, value))
+ }
+}
+
+impl<T> TryFrom<Vec<u8>> for HeaderField<T> {
+ type Error = IggyError;
+ fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
+ Self::try_from(value.as_slice())
+ }
+}
+
+impl<T> From<bool> for HeaderField<T> {
+ fn from(value: bool) -> Self {
+ Self::new_unchecked(HeaderKind::Bool, if value { &[1] } else { &[0] })
+ }
+}
+
+impl<T> From<i8> for HeaderField<T> {
+ fn from(value: i8) -> Self {
+ Self::new_unchecked(HeaderKind::Int8, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<i16> for HeaderField<T> {
+ fn from(value: i16) -> Self {
+ Self::new_unchecked(HeaderKind::Int16, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<i32> for HeaderField<T> {
+ fn from(value: i32) -> Self {
+ Self::new_unchecked(HeaderKind::Int32, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<i64> for HeaderField<T> {
+ fn from(value: i64) -> Self {
+ Self::new_unchecked(HeaderKind::Int64, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<i128> for HeaderField<T> {
+ fn from(value: i128) -> Self {
+ Self::new_unchecked(HeaderKind::Int128, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<u8> for HeaderField<T> {
+ fn from(value: u8) -> Self {
+ Self::new_unchecked(HeaderKind::Uint8, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<u16> for HeaderField<T> {
+ fn from(value: u16) -> Self {
+ Self::new_unchecked(HeaderKind::Uint16, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<u32> for HeaderField<T> {
+ fn from(value: u32) -> Self {
+ Self::new_unchecked(HeaderKind::Uint32, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<u64> for HeaderField<T> {
+ fn from(value: u64) -> Self {
+ Self::new_unchecked(HeaderKind::Uint64, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<u128> for HeaderField<T> {
+ fn from(value: u128) -> Self {
+ Self::new_unchecked(HeaderKind::Uint128, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<f32> for HeaderField<T> {
+ fn from(value: f32) -> Self {
+ Self::new_unchecked(HeaderKind::Float32, &value.to_le_bytes())
+ }
+}
+
+impl<T> From<f64> for HeaderField<T> {
+ fn from(value: f64) -> Self {
+ Self::new_unchecked(HeaderKind::Float64, &value.to_le_bytes())
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for bool {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_bool()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for bool {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_bool()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for i8 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int8()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for i8 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int8()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for i16 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int16()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for i16 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int16()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for i32 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int32()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for i32 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int32()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for i64 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int64()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for i64 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int64()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for i128 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int128()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for i128 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_int128()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for u8 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint8()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for u8 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint8()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for u16 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint16()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for u16 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint16()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for u32 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint32()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for u32 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint32()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for u64 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint64()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for u64 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint64()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for u128 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint128()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for u128 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_uint128()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for f32 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_float32()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for f32 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_float32()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for f64 {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_float64()
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for f64 {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_float64()
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for String {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_str().map(|s| s.to_owned())
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for String {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_str().map(|s| s.to_owned())
+ }
+}
+
+impl<T> TryFrom<HeaderField<T>> for Vec<u8> {
+ type Error = IggyError;
+ fn try_from(field: HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_raw().map(|s| s.to_vec())
+ }
+}
+
+impl<T> TryFrom<&HeaderField<T>> for Vec<u8> {
+ type Error = IggyError;
+ fn try_from(field: &HeaderField<T>) -> Result<Self, Self::Error> {
+ field.as_raw().map(|s| s.to_vec())
}
}
@@ -659,7 +1006,7 @@ mod tests {
#[test]
fn header_key_should_be_created_for_valid_value() {
let value = "key-1";
- let header_key = HeaderKey::from_string(value);
+ let header_key = HeaderKey::try_from(value);
assert!(header_key.is_ok());
let header_key = header_key.unwrap();
assert_eq!(header_key.kind, HeaderKind::String);
@@ -669,7 +1016,7 @@ mod tests {
#[test]
fn header_key_should_not_be_created_for_empty_value() {
let value = "";
- let header_key = HeaderKey::from_string(value);
+ let header_key = HeaderKey::try_from(value);
assert!(header_key.is_err());
let error = header_key.unwrap_err();
assert_eq!(error.as_code(), IggyError::InvalidHeaderValue.as_code());
@@ -678,7 +1025,7 @@ mod tests {
#[test]
fn header_key_should_not_be_created_for_too_long_value() {
let value = "a".repeat(256);
- let header_key = HeaderKey::from_string(&value);
+ let header_key = HeaderKey::try_from(value.as_str());
assert!(header_key.is_err());
let error = header_key.unwrap_err();
assert_eq!(error.as_code(), IggyError::InvalidHeaderValue.as_code());
@@ -687,16 +1034,14 @@ mod tests {
#[test]
fn header_key_should_be_created_from_int32() {
let value = 12345i32;
- let header_key = HeaderKey::from_int32(value);
- assert!(header_key.is_ok());
- let header_key = header_key.unwrap();
+ let header_key: HeaderKey = value.into();
assert_eq!(header_key.kind, HeaderKind::Int32);
assert_eq!(header_key.as_int32().unwrap(), value);
}
#[test]
fn header_value_should_not_be_created_for_empty_value() {
- let header_value = HeaderValue::from_raw(&[]);
+ let header_value = HeaderValue::try_from([].as_slice());
assert!(header_value.is_err());
let error = header_value.unwrap_err();
assert_eq!(error.as_code(), IggyError::InvalidHeaderValue.as_code());
@@ -705,7 +1050,7 @@ mod tests {
#[test]
fn header_value_should_not_be_created_for_too_long_value() {
let value = b"a".repeat(256);
- let header_value = HeaderValue::from_raw(&value);
+ let header_value = HeaderValue::try_from(value.as_slice());
assert!(header_value.is_err());
let error = header_value.unwrap_err();
assert_eq!(error.as_code(), IggyError::InvalidHeaderValue.as_code());
@@ -714,7 +1059,7 @@ mod tests {
#[test]
fn header_value_should_be_created_from_raw_bytes() {
let value = b"Value 1";
- let header_value = HeaderValue::from_raw(value);
+ let header_value = HeaderValue::try_from(value.as_slice());
assert!(header_value.is_ok());
assert_eq!(header_value.unwrap().value.as_ref(), value);
}
@@ -733,9 +1078,7 @@ mod tests {
#[test]
fn header_value_should_be_created_from_bool() {
let value = true;
- let header_value = HeaderValue::from_bool(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Bool);
assert_eq!(header_value.value.as_ref(), if value { [1] } else { [0] });
assert_eq!(header_value.as_bool().unwrap(), value);
@@ -743,10 +1086,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_int8() {
- let value = 123;
- let header_value = HeaderValue::from_int8(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: i8 = 123;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Int8);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_int8().unwrap(), value);
@@ -754,10 +1095,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_int16() {
- let value = 12345;
- let header_value = HeaderValue::from_int16(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: i16 = 12345;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Int16);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_int16().unwrap(), value);
@@ -765,10 +1104,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_int32() {
- let value = 123_456;
- let header_value = HeaderValue::from_int32(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: i32 = 123_456;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Int32);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_int32().unwrap(), value);
@@ -776,10 +1113,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_int64() {
- let value = 123_4567;
- let header_value = HeaderValue::from_int64(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: i64 = 123_4567;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Int64);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_int64().unwrap(), value);
@@ -787,10 +1122,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_int128() {
- let value = 1234_5678;
- let header_value = HeaderValue::from_int128(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: i128 = 1234_5678;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Int128);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_int128().unwrap(), value);
@@ -798,10 +1131,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_uint8() {
- let value = 123;
- let header_value = HeaderValue::from_uint8(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: u8 = 123;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Uint8);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_uint8().unwrap(), value);
@@ -809,10 +1140,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_uint16() {
- let value = 12345;
- let header_value = HeaderValue::from_uint16(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: u16 = 12345;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Uint16);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_uint16().unwrap(), value);
@@ -820,10 +1149,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_uint32() {
- let value = 123_456;
- let header_value = HeaderValue::from_uint32(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: u32 = 123_456;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Uint32);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_uint32().unwrap(), value);
@@ -831,10 +1158,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_uint64() {
- let value = 123_4567;
- let header_value = HeaderValue::from_uint64(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: u64 = 123_4567;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Uint64);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_uint64().unwrap(), value);
@@ -842,10 +1167,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_uint128() {
- let value = 1234_5678;
- let header_value = HeaderValue::from_uint128(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: u128 = 1234_5678;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Uint128);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_uint128().unwrap(), value);
@@ -853,10 +1176,8 @@ mod tests {
#[test]
fn header_value_should_be_created_from_float32() {
- let value = 123.01;
- let header_value = HeaderValue::from_float32(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let value: f32 = 123.01;
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Float32);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_float32().unwrap(), value);
@@ -864,250 +1185,13 @@ mod tests {
#[test]
fn header_value_should_be_created_from_float64() {
- let value = 1234.01234;
- let header_value = HeaderValue::from_float64(value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Float64);
- assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
- assert_eq!(header_value.as_float64().unwrap(), value);
- }
-
- #[test]
- fn header_value_should_be_created_string_from_kind_and_value_str() {
- let value = "Value 1";
- let header_value = HeaderValue::from_kind_str_and_value_str("string",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::String);
- assert_eq!(header_value.value, value.as_bytes());
- assert_eq!(header_value.as_str().unwrap(), value);
- }
-
- #[test]
- fn header_value_should_be_created_float_from_kind_and_value_str() {
let value: f64 = 1234.01234;
- let header_value = HeaderValue::from_kind_str_and_value_str("float64",
&value.to_string());
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
+ let header_value: HeaderValue = value.into();
assert_eq!(header_value.kind, HeaderKind::Float64);
assert_eq!(header_value.value.as_ref(), value.to_le_bytes());
assert_eq!(header_value.as_float64().unwrap(), value);
}
- #[test]
- fn header_value_should_be_created_raw_from_kind_and_value_str() {
- let value = "Value 1";
- let header_value = HeaderValue::from_kind_str_and_value_str("raw",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Raw);
- assert_eq!(header_value.value, value.as_bytes());
- }
-
- #[test]
- fn header_value_should_be_created_bool_from_kind_and_value_str() {
- let value = "true";
- let header_value = HeaderValue::from_kind_str_and_value_str("bool",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Bool);
- assert_eq!(header_value.value, vec![1]);
- assert!(header_value.as_bool().unwrap());
- }
-
- #[test]
- fn header_value_should_be_created_int8_from_kind_and_value_str() {
- let value = "123";
- let header_value = HeaderValue::from_kind_str_and_value_str("int8",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Int8);
- assert_eq!(header_value.value, vec![123]);
- assert_eq!(header_value.as_int8().unwrap(), 123);
- }
-
- #[test]
- fn header_value_should_be_created_int16_from_kind_and_value_str() {
- let value = "1234";
- let header_value = HeaderValue::from_kind_str_and_value_str("int16",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Int16);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<i16>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_int16().unwrap(),
- value.parse::<i16>().unwrap()
- );
- }
-
- #[test]
- fn header_value_should_be_created_int32_from_kind_and_value_str() {
- let value = "123456";
- let header_value = HeaderValue::from_kind_str_and_value_str("int32",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Int32);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<i32>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_int32().unwrap(),
- value.parse::<i32>().unwrap()
- );
- }
-
- #[test]
- fn header_value_should_be_created_int64_from_kind_and_value_str() {
- let value = "123456789";
- let header_value = HeaderValue::from_kind_str_and_value_str("int64",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Int64);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<i64>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_int64().unwrap(),
- value.parse::<i64>().unwrap()
- );
- }
-
- #[test]
- fn header_value_should_be_created_int128_from_kind_and_value_str() {
- let value = "123456789123456789";
- let header_value = HeaderValue::from_kind_str_and_value_str("int128",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Int128);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<i128>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_int128().unwrap(),
- value.parse::<i128>().unwrap()
- );
- }
-
- #[test]
- fn header_value_should_be_created_uint8_from_kind_and_value_str() {
- let value = "123";
- let header_value = HeaderValue::from_kind_str_and_value_str("uint8",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Uint8);
- assert_eq!(header_value.value, vec![123]);
- assert_eq!(header_value.as_uint8().unwrap(), 123);
- }
-
- #[test]
- fn header_value_should_be_created_uint16_from_kind_and_value_str() {
- let value = "12345";
- let header_value = HeaderValue::from_kind_str_and_value_str("uint16",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Uint16);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<u16>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_uint16().unwrap(),
- value.parse::<u16>().unwrap()
- );
- }
-
- #[test]
- fn header_value_should_be_created_uint32_from_kind_and_value_str() {
- let value = "123456";
- let header_value = HeaderValue::from_kind_str_and_value_str("uint32",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Uint32);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<u32>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_uint32().unwrap(),
- value.parse::<u32>().unwrap()
- );
- }
-
- #[test]
- fn header_value_should_be_created_uint64_from_kind_and_value_str() {
- let value = "123456789";
- let header_value = HeaderValue::from_kind_str_and_value_str("uint64",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Uint64);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<u64>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_uint64().unwrap(),
- value.parse::<u64>().unwrap()
- );
- }
-
- #[test]
- fn header_value_should_be_created_uint128_from_kind_and_value_str() {
- let value = "123456789123456789";
- let header_value = HeaderValue::from_kind_str_and_value_str("uint128",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Uint128);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<u128>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_uint128().unwrap(),
- value.parse::<u128>().unwrap()
- );
- }
-
- #[test]
- fn header_value_should_be_created_float32_from_kind_and_value_str() {
- let value = "123.01";
- let header_value = HeaderValue::from_kind_str_and_value_str("float32",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Float32);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<f32>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_float32().unwrap(),
- value.parse::<f32>().unwrap()
- );
- }
-
- #[test]
- fn header_value_should_be_created_float64_from_kind_and_value_str() {
- let value = "1234.01234";
- let header_value = HeaderValue::from_kind_str_and_value_str("float64",
value);
- assert!(header_value.is_ok());
- let header_value = header_value.unwrap();
- assert_eq!(header_value.kind, HeaderKind::Float64);
- assert_eq!(
- header_value.value.as_ref(),
- value.parse::<f64>().unwrap().to_le_bytes()
- );
- assert_eq!(
- header_value.as_float64().unwrap(),
- value.parse::<f64>().unwrap()
- );
- }
-
#[test]
fn to_string_value_for_string_kind() {
let header_value = HeaderValue::from_str("Hello").unwrap();
@@ -1116,79 +1200,79 @@ mod tests {
#[test]
fn to_string_value_for_bool_kind() {
- let header_value = HeaderValue::from_bool(true).unwrap();
+ let header_value: HeaderValue = true.into();
assert_eq!(header_value.to_string_value(), "true");
}
#[test]
fn to_string_value_for_int8_kind() {
- let header_value = HeaderValue::from_int8(123).unwrap();
+ let header_value: HeaderValue = 123i8.into();
assert_eq!(header_value.to_string_value(), "123");
}
#[test]
fn to_string_value_for_int16_kind() {
- let header_value = HeaderValue::from_int16(12345).unwrap();
+ let header_value: HeaderValue = 12345i16.into();
assert_eq!(header_value.to_string_value(), "12345");
}
#[test]
fn to_string_value_for_int32_kind() {
- let header_value = HeaderValue::from_int32(123456).unwrap();
+ let header_value: HeaderValue = 123456i32.into();
assert_eq!(header_value.to_string_value(), "123456");
}
#[test]
fn to_string_value_for_int64_kind() {
- let header_value = HeaderValue::from_int64(123456789).unwrap();
+ let header_value: HeaderValue = 123456789i64.into();
assert_eq!(header_value.to_string_value(), "123456789");
}
#[test]
fn to_string_value_for_int128_kind() {
- let header_value =
HeaderValue::from_int128(123456789123456789).unwrap();
+ let header_value: HeaderValue = 123456789123456789i128.into();
assert_eq!(header_value.to_string_value(), "123456789123456789");
}
#[test]
fn to_string_value_for_uint8_kind() {
- let header_value = HeaderValue::from_uint8(123).unwrap();
+ let header_value: HeaderValue = 123u8.into();
assert_eq!(header_value.to_string_value(), "123");
}
#[test]
fn to_string_value_for_uint16_kind() {
- let header_value = HeaderValue::from_uint16(12345).unwrap();
+ let header_value: HeaderValue = 12345u16.into();
assert_eq!(header_value.to_string_value(), "12345");
}
#[test]
fn to_string_value_for_uint32_kind() {
- let header_value = HeaderValue::from_uint32(123456).unwrap();
+ let header_value: HeaderValue = 123456u32.into();
assert_eq!(header_value.to_string_value(), "123456");
}
#[test]
fn to_string_value_for_uint64_kind() {
- let header_value = HeaderValue::from_uint64(123456789).unwrap();
+ let header_value: HeaderValue = 123456789u64.into();
assert_eq!(header_value.to_string_value(), "123456789");
}
#[test]
fn to_string_value_for_uint128_kind() {
- let header_value =
HeaderValue::from_uint128(123456789123456789).unwrap();
+ let header_value: HeaderValue = 123456789123456789u128.into();
assert_eq!(header_value.to_string_value(), "123456789123456789");
}
#[test]
fn to_string_value_for_float32_kind() {
- let header_value = HeaderValue::from_float32(123.01).unwrap();
+ let header_value: HeaderValue = 123.01f32.into();
assert_eq!(header_value.to_string_value(), "123.01");
}
#[test]
fn to_string_value_for_float64_kind() {
- let header_value = HeaderValue::from_float64(1234.01234).unwrap();
+ let header_value: HeaderValue = 1234.01234f64.into();
assert_eq!(header_value.to_string_value(), "1234.01234");
}
@@ -1196,17 +1280,11 @@ mod tests {
fn should_be_serialized_as_bytes() {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("key-1").unwrap(),
+ HeaderKey::try_from("key-1").unwrap(),
HeaderValue::from_str("Value 1").unwrap(),
);
- headers.insert(
- HeaderKey::from_string("key 1").unwrap(),
- HeaderValue::from_uint64(12345).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key_3").unwrap(),
- HeaderValue::from_bool(true).unwrap(),
- );
+ headers.insert(HeaderKey::try_from("key 1").unwrap(), 12345u64.into());
+ headers.insert(HeaderKey::try_from("key_3").unwrap(), true.into());
let bytes = headers.to_bytes();
@@ -1249,17 +1327,11 @@ mod tests {
fn should_be_deserialized_from_bytes() {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("key-1").unwrap(),
+ HeaderKey::try_from("key-1").unwrap(),
HeaderValue::from_str("Value 1").unwrap(),
);
- headers.insert(
- HeaderKey::from_string("key 2").unwrap(),
- HeaderValue::from_uint64(12345).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key_3").unwrap(),
- HeaderValue::from_bool(true).unwrap(),
- );
+ headers.insert(HeaderKey::try_from("key 2").unwrap(), 12345u64.into());
+ headers.insert(HeaderKey::try_from("key_3").unwrap(), true.into());
let mut bytes = BytesMut::new();
for (key, value) in &headers {
@@ -1290,13 +1362,10 @@ mod tests {
fn should_serialize_and_deserialize_typed_keys() {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_int32(123).unwrap(),
+ 123i32.into(),
HeaderValue::from_str("Value for int key").unwrap(),
);
- headers.insert(
- HeaderKey::from_uint64(999).unwrap(),
- HeaderValue::from_bool(true).unwrap(),
- );
+ headers.insert(999u64.into(), true.into());
let bytes = headers.to_bytes();
let deserialized = HashMap::<HeaderKey,
HeaderValue>::from_bytes(bytes).unwrap();
@@ -1310,4 +1379,164 @@ mod tests {
assert_eq!(deserialized_value.value, value.value);
}
}
+
+ #[test]
+ fn header_value_should_be_created_from_vec_u8() {
+ let value = vec![1u8, 2, 3, 4, 5];
+ let header_value = HeaderValue::try_from(value.clone());
+ assert!(header_value.is_ok());
+ let header_value = header_value.unwrap();
+ assert_eq!(header_value.kind, HeaderKind::Raw);
+ assert_eq!(header_value.value.as_ref(), value.as_slice());
+ assert_eq!(header_value.as_raw().unwrap(), value.as_slice());
+ }
+
+ #[test]
+ fn header_value_should_not_be_created_from_empty_vec_u8() {
+ let value: Vec<u8> = vec![];
+ let header_value = HeaderValue::try_from(value);
+ assert!(header_value.is_err());
+ let error = header_value.unwrap_err();
+ assert_eq!(error.as_code(), IggyError::InvalidHeaderValue.as_code());
+ }
+
+ #[test]
+ fn header_value_should_not_be_created_from_too_long_vec_u8() {
+ let value: Vec<u8> = vec![0u8; 256];
+ let header_value = HeaderValue::try_from(value);
+ assert!(header_value.is_err());
+ let error = header_value.unwrap_err();
+ assert_eq!(error.as_code(), IggyError::InvalidHeaderValue.as_code());
+ }
+
+ #[test]
+ fn header_key_should_be_created_from_vec_u8() {
+ let value = vec![1u8, 2, 3, 4];
+ let header_key = HeaderKey::try_from(value.clone());
+ assert!(header_key.is_ok());
+ let header_key = header_key.unwrap();
+ assert_eq!(header_key.kind, HeaderKind::Raw);
+ assert_eq!(header_key.value.as_ref(), value.as_slice());
+ }
+
+ #[test]
+ fn header_value_should_convert_to_bool() {
+ let header_value: HeaderValue = true.into();
+ let extracted: bool = header_value.try_into().unwrap();
+ assert!(extracted);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_i8() {
+ let header_value: HeaderValue = 42i8.into();
+ let extracted: i8 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 42);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_i16() {
+ let header_value: HeaderValue = 1234i16.into();
+ let extracted: i16 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 1234);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_i32() {
+ let header_value: HeaderValue = 123456i32.into();
+ let extracted: i32 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 123456);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_i64() {
+ let header_value: HeaderValue = 123456789i64.into();
+ let extracted: i64 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 123456789);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_i128() {
+ let header_value: HeaderValue = 123456789123456789i128.into();
+ let extracted: i128 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 123456789123456789);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_u8() {
+ let header_value: HeaderValue = 42u8.into();
+ let extracted: u8 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 42);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_u16() {
+ let header_value: HeaderValue = 1234u16.into();
+ let extracted: u16 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 1234);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_u32() {
+ let header_value: HeaderValue = 123456u32.into();
+ let extracted: u32 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 123456);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_u64() {
+ let header_value: HeaderValue = 123456789u64.into();
+ let extracted: u64 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 123456789);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_u128() {
+ let header_value: HeaderValue = 123456789123456789u128.into();
+ let extracted: u128 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 123456789123456789);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_f32() {
+ let header_value: HeaderValue = 123.5f32.into();
+ let extracted: f32 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 123.5);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_f64() {
+ let header_value: HeaderValue = 1234.5678f64.into();
+ let extracted: f64 = header_value.try_into().unwrap();
+ assert_eq!(extracted, 1234.5678);
+ }
+
+ #[test]
+ fn header_value_should_convert_to_string() {
+ let header_value = HeaderValue::try_from("hello").unwrap();
+ let extracted: String = header_value.try_into().unwrap();
+ assert_eq!(extracted, "hello");
+ }
+
+ #[test]
+ fn header_value_should_convert_to_vec_u8() {
+ let header_value = HeaderValue::try_from(vec![1u8, 2, 3]).unwrap();
+ let extracted: Vec<u8> = header_value.try_into().unwrap();
+ assert_eq!(extracted, vec![1u8, 2, 3]);
+ }
+
+ #[test]
+ fn header_value_should_fail_conversion_with_wrong_kind() {
+ let header_value: HeaderValue = 42i32.into();
+ let result: Result<u64, _> = header_value.try_into();
+ assert!(result.is_err());
+ }
+
+ #[test]
+ fn header_value_ref_should_convert_to_i32() {
+ let value = 123456i32;
+ let header_value: HeaderValue = value.into();
+ let extracted: i32 = (&header_value).try_into().unwrap();
+ assert_eq!(extracted, value);
+ assert_eq!(header_value.as_int32().unwrap(), value);
+ }
}
diff --git a/core/integration/tests/cli/message/test_message_poll_command.rs
b/core/integration/tests/cli/message/test_message_poll_command.rs
index 69f52e336..867a8aca1 100644
--- a/core/integration/tests/cli/message/test_message_poll_command.rs
+++ b/core/integration/tests/cli/message/test_message_poll_command.rs
@@ -195,7 +195,10 @@ impl IggyCmdTestCase for TestMessagePollCmd {
if self.show_headers {
status = status
- .stdout(contains(format!("Header: {}", self.headers.0)))
+ .stdout(contains(format!(
+ "Header: {}",
+ self.headers.0.to_string_value()
+ )))
.stdout(contains(self.headers.1.kind.to_string()))
.stdout(contains(self.headers.1.to_string_value()).count(self.message_count))
}
diff --git a/core/integration/tests/cli/message/test_message_send_command.rs
b/core/integration/tests/cli/message/test_message_send_command.rs
index b0dcb27b6..fea3498e5 100644
--- a/core/integration/tests/cli/message/test_message_send_command.rs
+++ b/core/integration/tests/cli/message/test_message_send_command.rs
@@ -109,7 +109,9 @@ impl TestMessageSendCmd {
command.push(
header
.iter()
- .map(|(k, v)| format!("{k}:{}:{}", v.kind,
v.to_string_value()))
+ .map(|(k, v)| {
+ format!("{}:{}:{}", k.to_string_value(), v.kind,
v.to_string_value())
+ })
.collect::<Vec<_>>()
.join(","),
);
@@ -340,13 +342,10 @@ pub async fn should_be_successful() {
using_partitioning,
Some(HashMap::from([
(
- HeaderKey::from_string("key1").unwrap(),
- HeaderValue::from_kind_str_and_value_str("string",
"value1").unwrap(),
- ),
- (
- HeaderKey::from_string("key2").unwrap(),
- HeaderValue::from_kind_str_and_value_str("int32",
"42").unwrap(),
+ HeaderKey::try_from("key1").unwrap(),
+ HeaderValue::try_from("value1").unwrap(),
),
+ (HeaderKey::try_from("key2").unwrap(), 42i32.into()),
])),
))
.await;
diff --git a/core/integration/tests/server/scenarios/create_message_payload.rs
b/core/integration/tests/server/scenarios/create_message_payload.rs
index 20d1127af..1add0b0f7 100644
--- a/core/integration/tests/server/scenarios/create_message_payload.rs
+++ b/core/integration/tests/server/scenarios/create_message_payload.rs
@@ -20,7 +20,6 @@ use bytes::Bytes;
use iggy::prelude::*;
use integration::test_server::{ClientFactory, assert_clean_system, login_root};
use std::collections::HashMap;
-use std::str::FromStr;
const STREAM_NAME: &str = "test-stream";
const TOPIC_NAME: &str = "test-topic";
@@ -82,7 +81,7 @@ pub async fn run(client_factory: &dyn ClientFactory) {
assert_eq!(headers.len(), 3);
assert_eq!(
headers
- .get(&HeaderKey::from_string("key_1").unwrap())
+ .get(&HeaderKey::try_from("key_1").unwrap())
.unwrap()
.as_str()
.unwrap(),
@@ -90,14 +89,14 @@ pub async fn run(client_factory: &dyn ClientFactory) {
);
assert!(
headers
- .get(&HeaderKey::from_string("key 2").unwrap())
+ .get(&HeaderKey::try_from("key 2").unwrap())
.unwrap()
.as_bool()
.unwrap(),
);
assert_eq!(
headers
- .get(&HeaderKey::from_string("key-3").unwrap())
+ .get(&HeaderKey::try_from("key-3").unwrap())
.unwrap()
.as_uint64()
.unwrap(),
@@ -141,16 +140,10 @@ fn create_message_payload(offset: u64) -> Bytes {
fn create_message_headers() -> HashMap<HeaderKey, HeaderValue> {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("key_1").unwrap(),
- HeaderValue::from_str("Value 1").unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key 2").unwrap(),
- HeaderValue::from_bool(true).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key-3").unwrap(),
- HeaderValue::from_uint64(123456).unwrap(),
+ HeaderKey::try_from("key_1").unwrap(),
+ HeaderValue::try_from("Value 1").unwrap(),
);
+ headers.insert(HeaderKey::try_from("key 2").unwrap(), true.into());
+ headers.insert(HeaderKey::try_from("key-3").unwrap(), 123456u64.into());
headers
}
diff --git a/core/integration/tests/server/scenarios/encryption_scenario.rs
b/core/integration/tests/server/scenarios/encryption_scenario.rs
index 23dd5c19c..49f608173 100644
--- a/core/integration/tests/server/scenarios/encryption_scenario.rs
+++ b/core/integration/tests/server/scenarios/encryption_scenario.rs
@@ -23,7 +23,7 @@ use integration::{
test_server::{ClientFactory, IpAddrKind, SYSTEM_PATH_ENV_VAR, TestServer,
login_root},
};
use serial_test::parallel;
-use std::{collections::HashMap, str::FromStr};
+use std::collections::HashMap;
use test_case::test_matrix;
fn encryption_enabled() -> bool {
@@ -97,22 +97,13 @@ async fn
should_fill_data_with_headers_and_verify_after_restart_using_api(encryp
for i in 0..messages_per_batch {
let mut headers = HashMap::new();
+ headers.insert(HeaderKey::try_from("batch").unwrap(), 1u64.into());
+ headers.insert(HeaderKey::try_from("index").unwrap(), i.into());
headers.insert(
- HeaderKey::from_string("batch").unwrap(),
- HeaderValue::from_uint64(1).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("index").unwrap(),
- HeaderValue::from_uint64(i).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("type").unwrap(),
- HeaderValue::from_str("test-message").unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("encrypted").unwrap(),
- HeaderValue::from_bool(encryption).unwrap(),
+ HeaderKey::try_from("type").unwrap(),
+ HeaderValue::try_from("test-message").unwrap(),
);
+ headers.insert(HeaderKey::try_from("encrypted").unwrap(),
encryption.into());
let message = IggyMessage::builder()
.id((i + 1) as u128)
@@ -195,7 +186,7 @@ async fn
should_fill_data_with_headers_and_verify_after_restart_using_api(encryp
let headers = msg.user_headers_map().unwrap().unwrap();
assert_eq!(
headers
- .get(&HeaderKey::from_string("batch").unwrap())
+ .get(&HeaderKey::try_from("batch").unwrap())
.unwrap()
.as_uint64()
.unwrap(),
@@ -203,7 +194,7 @@ async fn
should_fill_data_with_headers_and_verify_after_restart_using_api(encryp
);
assert_eq!(
headers
- .get(&HeaderKey::from_string("type").unwrap())
+ .get(&HeaderKey::try_from("type").unwrap())
.unwrap()
.as_str()
.unwrap(),
@@ -211,7 +202,7 @@ async fn
should_fill_data_with_headers_and_verify_after_restart_using_api(encryp
);
assert_eq!(
headers
- .get(&HeaderKey::from_string("encrypted").unwrap())
+ .get(&HeaderKey::try_from("encrypted").unwrap())
.unwrap()
.as_bool()
.unwrap(),
@@ -242,22 +233,13 @@ async fn
should_fill_data_with_headers_and_verify_after_restart_using_api(encryp
for i in 0..messages_per_batch {
let mut headers = HashMap::new();
+ headers.insert(HeaderKey::try_from("batch").unwrap(), 2u64.into());
+ headers.insert(HeaderKey::try_from("index").unwrap(), i.into());
headers.insert(
- HeaderKey::from_string("batch").unwrap(),
- HeaderValue::from_uint64(2).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("index").unwrap(),
- HeaderValue::from_uint64(i).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("type").unwrap(),
- HeaderValue::from_str("test-message-after-restart").unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("encrypted").unwrap(),
- HeaderValue::from_bool(encryption).unwrap(),
+ HeaderKey::try_from("type").unwrap(),
+ HeaderValue::try_from("test-message-after-restart").unwrap(),
);
+ headers.insert(HeaderKey::try_from("encrypted").unwrap(),
encryption.into());
let message = IggyMessage::builder()
.id((messages_per_batch + i + 1) as u128)
@@ -322,7 +304,7 @@ async fn
should_fill_data_with_headers_and_verify_after_restart_using_api(encryp
assert!(msg.user_headers.is_some());
let headers = msg.user_headers_map().unwrap().unwrap();
let batch_num = headers
- .get(&HeaderKey::from_string("batch").unwrap())
+ .get(&HeaderKey::try_from("batch").unwrap())
.unwrap()
.as_uint64()
.unwrap();
@@ -331,7 +313,7 @@ async fn
should_fill_data_with_headers_and_verify_after_restart_using_api(encryp
batch_1_count += 1;
assert_eq!(
headers
- .get(&HeaderKey::from_string("type").unwrap())
+ .get(&HeaderKey::try_from("type").unwrap())
.unwrap()
.as_str()
.unwrap(),
@@ -339,7 +321,7 @@ async fn
should_fill_data_with_headers_and_verify_after_restart_using_api(encryp
);
assert_eq!(
headers
- .get(&HeaderKey::from_string("encrypted").unwrap())
+ .get(&HeaderKey::try_from("encrypted").unwrap())
.unwrap()
.as_bool()
.unwrap(),
@@ -349,7 +331,7 @@ async fn
should_fill_data_with_headers_and_verify_after_restart_using_api(encryp
batch_2_count += 1;
assert_eq!(
headers
- .get(&HeaderKey::from_string("type").unwrap())
+ .get(&HeaderKey::try_from("type").unwrap())
.unwrap()
.as_str()
.unwrap(),
diff --git
a/core/integration/tests/server/scenarios/message_headers_scenario.rs
b/core/integration/tests/server/scenarios/message_headers_scenario.rs
index 4de9afb29..1d8b1e190 100644
--- a/core/integration/tests/server/scenarios/message_headers_scenario.rs
+++ b/core/integration/tests/server/scenarios/message_headers_scenario.rs
@@ -23,7 +23,6 @@ use bytes::Bytes;
use iggy::prelude::*;
use integration::test_server::{ClientFactory, assert_clean_system, login_root};
use std::collections::HashMap;
-use std::str::FromStr;
pub async fn run(client_factory: &dyn ClientFactory) {
let client = create_client(client_factory).await;
@@ -79,7 +78,7 @@ pub async fn run(client_factory: &dyn ClientFactory) {
assert_eq!(headers.len(), 3);
assert_eq!(
headers
- .get(&HeaderKey::from_string("key_1").unwrap())
+ .get(&HeaderKey::try_from("key_1").unwrap())
.unwrap()
.as_str()
.unwrap(),
@@ -87,14 +86,14 @@ pub async fn run(client_factory: &dyn ClientFactory) {
);
assert!(
headers
- .get(&HeaderKey::from_string("key 2").unwrap())
+ .get(&HeaderKey::try_from("key 2").unwrap())
.unwrap()
.as_bool()
.unwrap(),
);
assert_eq!(
headers
- .get(&HeaderKey::from_string("key-3").unwrap())
+ .get(&HeaderKey::try_from("key-3").unwrap())
.unwrap()
.as_uint64()
.unwrap(),
@@ -131,16 +130,10 @@ fn create_message_payload(offset: u64) -> Bytes {
fn create_message_headers() -> HashMap<HeaderKey, HeaderValue> {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("key_1").unwrap(),
- HeaderValue::from_str("Value 1").unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key 2").unwrap(),
- HeaderValue::from_bool(true).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key-3").unwrap(),
- HeaderValue::from_uint64(123456).unwrap(),
+ HeaderKey::try_from("key_1").unwrap(),
+ HeaderValue::try_from("Value 1").unwrap(),
);
+ headers.insert(HeaderKey::try_from("key 2").unwrap(), true.into());
+ headers.insert(HeaderKey::try_from("key-3").unwrap(), 123456u64.into());
headers
}
diff --git a/core/integration/tests/server/scenarios/message_size_scenario.rs
b/core/integration/tests/server/scenarios/message_size_scenario.rs
index 04f831b18..f63b0570b 100644
--- a/core/integration/tests/server/scenarios/message_size_scenario.rs
+++ b/core/integration/tests/server/scenarios/message_size_scenario.rs
@@ -20,7 +20,6 @@ use bytes::Bytes;
use iggy::prelude::*;
use integration::test_server::{ClientFactory, assert_clean_system, login_root};
use std::collections::HashMap;
-use std::str::FromStr;
const STREAM_NAME: &str = "test-stream";
const TOPIC_NAME: &str = "test-topic";
@@ -222,8 +221,8 @@ fn create_message_header_of_size(target_size: usize) ->
HashMap<HeaderKey, Heade
remaining_size - header_overhead
};
- let key = HeaderKey::from_raw(&key_bytes).unwrap();
- let value =
HeaderValue::from_str(create_string_of_size(value_size).as_str()).unwrap();
+ let key = HeaderKey::try_from(key_bytes.as_slice()).unwrap();
+ let value =
HeaderValue::try_from(create_string_of_size(value_size).as_str()).unwrap();
let actual_header_size = header_overhead + value_size;
current_size += actual_header_size;
diff --git a/core/integration/tests/server/scenarios/offset_scenario.rs
b/core/integration/tests/server/scenarios/offset_scenario.rs
index dd35892c8..608b1b3fb 100644
--- a/core/integration/tests/server/scenarios/offset_scenario.rs
+++ b/core/integration/tests/server/scenarios/offset_scenario.rs
@@ -21,7 +21,6 @@ use bytes::BytesMut;
use iggy::prelude::*;
use integration::test_server::{ClientFactory, login_root};
use std::collections::HashMap;
-use std::str::FromStr;
fn small_batches() -> Vec<u32> {
vec![3, 4, 5, 6, 7]
@@ -174,17 +173,11 @@ fn create_single_message(id: u32, message_size: u64) ->
IggyMessage {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("key_1").unwrap(),
- HeaderValue::from_str("Value 1").unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key 2").unwrap(),
- HeaderValue::from_bool(true).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key-3").unwrap(),
- HeaderValue::from_uint64(123456).unwrap(),
+ HeaderKey::try_from("key_1").unwrap(),
+ HeaderValue::try_from("Value 1").unwrap(),
);
+ headers.insert(HeaderKey::try_from("key 2").unwrap(), true.into());
+ headers.insert(HeaderKey::try_from("key-3").unwrap(), 123456u64.into());
IggyMessage::builder()
.id(id as u128)
diff --git a/core/integration/tests/server/scenarios/timestamp_scenario.rs
b/core/integration/tests/server/scenarios/timestamp_scenario.rs
index d8ddfe109..eb5129701 100644
--- a/core/integration/tests/server/scenarios/timestamp_scenario.rs
+++ b/core/integration/tests/server/scenarios/timestamp_scenario.rs
@@ -21,7 +21,6 @@ use bytes::BytesMut;
use iggy::prelude::*;
use integration::test_server::{ClientFactory, login_root};
use std::collections::HashMap;
-use std::str::FromStr;
use tokio::time::{Duration, sleep};
fn small_batches() -> Vec<u32> {
@@ -198,17 +197,11 @@ fn create_single_message(id: u32, message_size: u64) ->
IggyMessage {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("key_1").unwrap(),
- HeaderValue::from_str("Value 1").unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key 2").unwrap(),
- HeaderValue::from_bool(true).unwrap(),
- );
- headers.insert(
- HeaderKey::from_string("key-3").unwrap(),
- HeaderValue::from_uint64(123456).unwrap(),
+ HeaderKey::try_from("key_1").unwrap(),
+ HeaderValue::try_from("Value 1").unwrap(),
);
+ headers.insert(HeaderKey::try_from("key 2").unwrap(), true.into());
+ headers.insert(HeaderKey::try_from("key-3").unwrap(), 123456u64.into());
IggyMessage::builder()
.id(id as u128)
diff --git a/core/sdk/src/prelude.rs b/core/sdk/src/prelude.rs
index ba374fe6b..bcbb44f82 100644
--- a/core/sdk/src/prelude.rs
+++ b/core/sdk/src/prelude.rs
@@ -57,12 +57,12 @@ pub use iggy_common::{
Aes256GcmEncryptor, Args, ArgsOptional, AutoLogin, BytesSerializable,
CacheMetrics,
CacheMetricsKey, ClientError, ClientInfoDetails, ClusterMetadata,
ClusterNode, ClusterNodeRole,
ClusterNodeStatus, CompressionAlgorithm, Consumer, ConsumerGroupDetails,
ConsumerKind,
- EncryptorKind, FlushUnsavedBuffer, GlobalPermissions, HeaderKey,
HeaderValue, HttpClientConfig,
- HttpClientConfigBuilder, IdKind, Identifier, IdentityInfo, IggyByteSize,
IggyDuration,
- IggyError, IggyExpiry, IggyIndexView, IggyMessage, IggyMessageHeader,
IggyMessageHeaderView,
- IggyMessageView, IggyMessageViewIterator, IggyTimestamp, MaxTopicSize,
Partition, Partitioner,
- Partitioning, Permissions, PersonalAccessTokenExpiry, PollMessages,
PolledMessages,
- PollingKind, PollingStrategy, QuicClientConfig, QuicClientConfigBuilder,
+ EncryptorKind, FlushUnsavedBuffer, GlobalPermissions, HeaderKey,
HeaderKind, HeaderValue,
+ HttpClientConfig, HttpClientConfigBuilder, IdKind, Identifier,
IdentityInfo, IggyByteSize,
+ IggyDuration, IggyError, IggyExpiry, IggyIndexView, IggyMessage,
IggyMessageHeader,
+ IggyMessageHeaderView, IggyMessageView, IggyMessageViewIterator,
IggyTimestamp, MaxTopicSize,
+ Partition, Partitioner, Partitioning, Permissions,
PersonalAccessTokenExpiry, PollMessages,
+ PolledMessages, PollingKind, PollingStrategy, QuicClientConfig,
QuicClientConfigBuilder,
QuicClientReconnectionConfig, SendMessages, Sizeable, SnapshotCompression,
Stats, Stream,
StreamDetails, StreamPermissions, SystemSnapshotType, TcpClientConfig,
TcpClientConfigBuilder,
TcpClientReconnectionConfig, Topic, TopicDetails, TopicPermissions,
TransportEndpoints,
diff --git a/core/server/server.http b/core/server/server.http
index 02a7d2d13..a2dbabf9c 100644
--- a/core/server/server.http
+++ b/core/server/server.http
@@ -25,7 +25,10 @@
@partition_id_payload_base64 = AAAAAA==
@message_1_payload_base64 = aGVsbG8=
@message_2_payload_base64 = d29ybGQ=
-@header_1_payload_base_64 = dmFsdWUgMQ==
+@header_key_1_base64 = a2V5XzE=
+@header_value_1_base64 = dmFsdWUgMQ==
+@header_key_2_base64 = Kg==
+@header_value_2_base64 = AAAA
@root_username = iggy
@root_password = iggy
@user1_username = user1
@@ -301,12 +304,25 @@ Content-Type: application/json
}, {
"id": 0,
"payload": "{{message_2_payload_base64}}",
- "headers": {
- "key_1": {
+ "user_headers": [{
+ "key": {
"kind": "string",
- "value": "{{header_1_payload_base_64}}"
+ "value": "{{header_key_1_base64}}"
+ },
+ "value": {
+ "kind": "string",
+ "value": "{{header_value_1_base64}}"
}
- }
+ }, {
+ "key": {
+ "kind": "uint32",
+ "value": "{{header_key_2_base64}}"
+ },
+ "value": {
+ "kind": "int32",
+ "value": "{{header_value_2_base64}}"
+ }
+ }]
}]
}
diff --git a/core/tools/src/data-seeder/seeder.rs
b/core/tools/src/data-seeder/seeder.rs
index 045cd3ffc..edbac98dc 100644
--- a/core/tools/src/data-seeder/seeder.rs
+++ b/core/tools/src/data-seeder/seeder.rs
@@ -19,7 +19,6 @@
use iggy::prelude::*;
use rand::Rng;
use std::collections::HashMap;
-use std::str::FromStr;
const PROD_STREAM_NAME: &str = "prod";
const TEST_STREAM_NAME: &str = "test";
@@ -158,17 +157,11 @@ async fn send_messages(client: &IggyClient, streams:
&[(String, u32)]) -> Result
true => {
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("key 1")?,
- HeaderValue::from_str("value1")?,
- );
- headers.insert(
- HeaderKey::from_string("key-2")?,
- HeaderValue::from_bool(true)?,
- );
- headers.insert(
- HeaderKey::from_string("key_3")?,
- HeaderValue::from_uint64(123456)?,
+ HeaderKey::try_from("key 1")?,
+ HeaderValue::try_from("value1")?,
);
+ headers.insert(HeaderKey::try_from("key-2")?,
true.into());
+ headers.insert(HeaderKey::try_from("key_3")?,
123456u64.into());
Some(headers)
}
};
diff --git a/examples/rust/src/message-headers/message-type/consumer/main.rs
b/examples/rust/src/message-headers/message-type/consumer/main.rs
index bdc6bb451..8ac62ffbf 100644
--- a/examples/rust/src/message-headers/message-type/consumer/main.rs
+++ b/examples/rust/src/message-headers/message-type/consumer/main.rs
@@ -51,7 +51,7 @@ fn handle_message(message: &IggyMessage) -> Result<(),
Box<dyn Error>> {
// The payload can be of any type as it is a raw byte array. In this case
it's a JSON string.
let payload = std::str::from_utf8(&message.payload)?;
// The message type is stored in the custom message header.
- let header_key = HeaderKey::from_string("message_type").unwrap();
+ let header_key = HeaderKey::try_from("message_type").unwrap();
let headers_map = message.user_headers_map()?.unwrap();
let message_type = headers_map.get(&header_key).unwrap().as_str()?;
info!(
diff --git a/examples/rust/src/message-headers/message-type/producer/main.rs
b/examples/rust/src/message-headers/message-type/producer/main.rs
index 680b56bd4..f394fddfe 100644
--- a/examples/rust/src/message-headers/message-type/producer/main.rs
+++ b/examples/rust/src/message-headers/message-type/producer/main.rs
@@ -24,7 +24,6 @@ use
iggy_examples::shared::messages_generator::MessagesGenerator;
use iggy_examples::shared::system;
use std::collections::HashMap;
use std::error::Error;
-use std::str::FromStr;
use std::sync::Arc;
use tracing::info;
use tracing_subscriber::layer::SubscriberExt;
@@ -86,8 +85,8 @@ async fn produce_messages(args: &Args, client: &IggyClient)
-> Result<(), Box<dy
// The message type will be stored in the custom message header.
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("message_type").unwrap(),
- HeaderValue::from_str(message_type).unwrap(),
+ HeaderKey::try_from("message_type").unwrap(),
+ HeaderValue::try_from(message_type).unwrap(),
);
let message = IggyMessage::builder()
diff --git a/examples/rust/src/message-headers/typed-headers/producer/main.rs
b/examples/rust/src/message-headers/typed-headers/producer/main.rs
index 60d86687a..3e6d3c5a8 100644
--- a/examples/rust/src/message-headers/typed-headers/producer/main.rs
+++ b/examples/rust/src/message-headers/typed-headers/producer/main.rs
@@ -80,28 +80,22 @@ async fn produce_messages(args: &Args, client: &IggyClient)
-> Result<(), Box<dy
let mut headers = HashMap::new();
headers.insert(
- HeaderKey::from_string("event_type")?,
- HeaderValue::from_string("user_action")?,
+ HeaderKey::try_from("event_type")?,
+ HeaderValue::try_from("user_action")?,
);
+ headers.insert(1u32.into(), message_id.into());
headers.insert(
- HeaderKey::from_uint32(1)?,
- HeaderValue::from_uint64(message_id)?,
+ HeaderKey::try_from("important")?,
+ message_id.is_multiple_of(5).into(),
);
+ headers.insert(44u32.into(), (message_id as f64 * 2.0).into());
headers.insert(
- HeaderKey::from_string("important")?,
- HeaderValue::from_bool(message_id.is_multiple_of(5))?,
+ HeaderKey::try_from("trace_id")?,
+ (message_id as i128 * 1_000_000_000_000).into(),
);
headers.insert(
- HeaderKey::from_uint32(44)?,
- HeaderValue::from_float64(message_id as f64 * 2.0)?,
- );
- headers.insert(
- HeaderKey::from_string("trace_id")?,
- HeaderValue::from_int128(message_id as i128 *
1_000_000_000_000)?,
- );
- headers.insert(
- HeaderKey::from_raw(&[0xDE, 0xAD])?,
- HeaderValue::from_raw(&[0xBE, 0xEF, 0xCA, 0xFE])?,
+ HeaderKey::try_from([0xDE, 0xAD].as_slice())?,
+ HeaderValue::try_from([0xBE, 0xEF, 0xCA, 0xFE].as_slice())?,
);
let payload =
diff --git a/examples/rust/src/shared/codec.rs
b/examples/rust/src/shared/codec.rs
index b5d5aa1dc..3625be417 100644
--- a/examples/rust/src/shared/codec.rs
+++ b/examples/rust/src/shared/codec.rs
@@ -57,13 +57,13 @@ impl FromStr for Codec {
impl Codec {
/// Returns the key to indicate compressed messages as HeaderKey.
pub fn header_key() -> HeaderKey {
- HeaderKey::from_string(COMPRESSION_HEADER_KEY)
+ HeaderKey::try_from(COMPRESSION_HEADER_KEY)
.expect("COMPRESSION_HEADER_KEY is an InvalidHeaderKey.")
}
/// Returns the compression algorithm type as HeaderValue.
pub fn to_header_value(&self) -> HeaderValue {
- HeaderValue::from_str(&self.to_string()).expect("failed generating
HeaderValue.")
+ HeaderValue::try_from(self.to_string()).expect("failed generating
HeaderValue.")
}
/// Returns a Codec from a HeaderValue. Used when reading messages from
the server.
diff --git a/foreign/csharp/Iggy_SDK/JsonConverters/MessageConverter.cs
b/foreign/csharp/Iggy_SDK/JsonConverters/MessageConverter.cs
index 4a9331398..43b2163ce 100644
--- a/foreign/csharp/Iggy_SDK/JsonConverters/MessageConverter.cs
+++ b/foreign/csharp/Iggy_SDK/JsonConverters/MessageConverter.cs
@@ -54,11 +54,11 @@ internal sealed class MessageConverter :
JsonConverter<Message>
{
if (userHeaders is null)
{
- writer.WriteNull("headers");
+ writer.WriteNull("user_headers");
return;
}
- writer.WriteStartArray("headers");
+ writer.WriteStartArray("user_headers");
foreach (var (headerKey, headerValue) in userHeaders)
{