Skip to main content

osom_lib_primitives/
kvp.rs

1//! Holds the [`KVP (Key-Value Pair)`][KVP] struct and its implementation.
2use core::fmt::Display;
3
4use osom_lib_reprc::traits::ReprC;
5use osom_lib_try_clone::TryClone;
6
7/// Represents possible errors when trying to clone a [`KVP`].
8#[repr(C)]
9#[repr(u8)]
10#[derive(Debug, PartialEq, Eq, Hash, Clone)]
11#[must_use]
12#[allow(clippy::upper_case_acronyms)]
13pub enum KVPTryCloneError<TKeyError, TValueError> {
14    /// Cloning the key failed.
15    KeyCloneError(TKeyError) = 0,
16
17    /// Cloning the value failed.
18    ValueError(TValueError) = 1,
19}
20
21/// Represents the `(key, value)` pair, but with `#[repr(C)]` ABI.
22#[repr(C)]
23#[must_use]
24#[derive(Debug, PartialEq, Eq, Hash)]
25#[allow(clippy::upper_case_acronyms)]
26pub struct KVP<TKey, TValue> {
27    pub key: TKey,
28    pub value: TValue,
29}
30
31unsafe impl<TKey: ReprC, TValue: ReprC> ReprC for KVP<TKey, TValue> {
32    const CHECK: () = const {
33        osom_lib_reprc::hidden::is_reprc::<TKey>();
34        osom_lib_reprc::hidden::is_reprc::<TValue>();
35    };
36}
37
38impl<TKey, TValue> KVP<TKey, TValue> {
39    /// Unpacks the [`KVP`] and returns the key and value as a tuple.
40    #[inline]
41    #[must_use]
42    pub const fn unpack(self) -> (TKey, TValue) {
43        let key = unsafe { core::ptr::read(&raw const self.key) };
44        let value = unsafe { core::ptr::read(&raw const self.value) };
45        core::mem::forget(self);
46        (key, value)
47    }
48
49    /// Unpacks the [`KVP`] from a raw pointer and returns the key and value as a tuple of raw pointers.
50    ///
51    /// # Safety
52    ///
53    /// It is up to the caller to ensure that `ptr` is a valid, non-null pointer to a [`KVP`].
54    #[inline(always)]
55    #[must_use]
56    pub const unsafe fn unpack_ptr(ptr: *mut Self) -> (*mut TKey, *mut TValue) {
57        unsafe {
58            let mut_ref = ptr.as_mut_unchecked();
59            (&raw mut mut_ref.key, &raw mut mut_ref.value)
60        }
61    }
62
63    /// Converts reference to [`KVP`] into [`KVP`] of references.
64    #[inline(always)]
65    pub const fn as_ref_kvp(&self) -> KVP<&TKey, &TValue> {
66        KVP {
67            key: &self.key,
68            value: &self.value,
69        }
70    }
71
72    /// Converts mutable reference to [`KVP`] into [`KVP`] with
73    /// key as a reference and value as a mutable reference.
74    #[inline(always)]
75    pub const fn as_mut_kvp(&mut self) -> KVP<&TKey, &mut TValue> {
76        KVP {
77            key: &self.key,
78            value: &mut self.value,
79        }
80    }
81
82    /// Returns references to the key and value as a tuple.
83    #[inline]
84    #[must_use]
85    pub const fn as_tuple(&self) -> (&TKey, &TValue) {
86        (&self.key, &self.value)
87    }
88
89    /// Returns mutable references to the key and value as a tuple.
90    #[inline]
91    #[must_use]
92    pub const fn as_mut_tuple(&mut self) -> (&mut TKey, &mut TValue) {
93        (&mut self.key, &mut self.value)
94    }
95}
96
97impl<TKey: Display, TValue: Display> Display for KVP<TKey, TValue> {
98    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
99        write!(f, "KVP(key: {}, value: {})", self.key, self.value)
100    }
101}
102
103impl<TKey, TValue> From<(TKey, TValue)> for KVP<TKey, TValue> {
104    fn from((key, value): (TKey, TValue)) -> Self {
105        Self { key, value }
106    }
107}
108
109impl<TKey, TValue> From<KVP<TKey, TValue>> for (TKey, TValue) {
110    fn from(kvp: KVP<TKey, TValue>) -> Self {
111        kvp.unpack()
112    }
113}
114
115impl<TKey: TryClone, TValue: TryClone> TryClone for KVP<TKey, TValue> {
116    type Error = KVPTryCloneError<TKey::Error, TValue::Error>;
117
118    fn try_clone(&self) -> Result<Self, Self::Error> {
119        Ok(Self {
120            key: self.key.try_clone().map_err(KVPTryCloneError::KeyCloneError)?,
121            value: self.value.try_clone().map_err(KVPTryCloneError::ValueError)?,
122        })
123    }
124}
125
126impl<TKey: TryClone, TValue: TryClone> Clone for KVP<TKey, TValue> {
127    fn clone(&self) -> Self {
128        self.try_clone().expect("[KVP::clone] failure")
129    }
130}