etcd_client/rpc/
mod.rs

1//! Etcd RPC interfaces.
2
3#[cfg(feature = "pub-response-field")]
4pub(crate) mod pb;
5
6#[cfg(not(feature = "pub-response-field"))]
7mod pb;
8
9pub mod auth;
10pub mod cluster;
11pub mod election;
12pub mod kv;
13pub mod lease;
14pub mod lock;
15pub mod maintenance;
16pub mod watch;
17
18use crate::error::Result;
19use pb::etcdserverpb::ResponseHeader as PbResponseHeader;
20use pb::mvccpb::KeyValue as PbKeyValue;
21
22/// General `etcd` response header.
23#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
24#[derive(Debug, Clone)]
25#[repr(transparent)]
26pub struct ResponseHeader(PbResponseHeader);
27
28impl ResponseHeader {
29    /// Create a response header from pb header.
30    #[inline]
31    pub(crate) const fn new(header: PbResponseHeader) -> Self {
32        Self(header)
33    }
34
35    /// The ID of the cluster which sent the response.
36    #[inline]
37    pub const fn cluster_id(&self) -> u64 {
38        self.0.cluster_id
39    }
40
41    /// The ID of the member which sent the response.
42    #[inline]
43    pub const fn member_id(&self) -> u64 {
44        self.0.member_id
45    }
46
47    /// The key-value store revision when the request was applied.
48    /// For watch progress responses, the header.revision() indicates progress. All future events
49    /// received in this stream are guaranteed to have a higher revision number than the
50    /// header.revision() number.
51    #[inline]
52    pub const fn revision(&self) -> i64 {
53        self.0.revision
54    }
55
56    /// The raft term when the request was applied.
57    #[inline]
58    pub const fn raft_term(&self) -> u64 {
59        self.0.raft_term
60    }
61}
62
63impl From<&PbResponseHeader> for &ResponseHeader {
64    #[inline]
65    fn from(src: &PbResponseHeader) -> Self {
66        unsafe { &*(src as *const _ as *const ResponseHeader) }
67    }
68}
69
70/// Key-value pair.
71#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
72#[derive(Debug, Clone)]
73#[repr(transparent)]
74pub struct KeyValue(PbKeyValue);
75
76impl KeyValue {
77    /// Create a KeyValue from pb kv.
78    #[inline]
79    pub(crate) const fn new(kv: PbKeyValue) -> Self {
80        Self(kv)
81    }
82
83    /// The key in bytes. An empty key is not allowed.
84    #[inline]
85    pub fn key(&self) -> &[u8] {
86        &self.0.key
87    }
88
89    /// The key in string. An empty key is not allowed.
90    #[inline]
91    pub fn key_str(&self) -> Result<&str> {
92        std::str::from_utf8(self.key()).map_err(From::from)
93    }
94
95    /// The key in string. An empty key is not allowed.
96    ///
97    /// # Safety
98    /// This function is unsafe because it does not check that the bytes of the key are valid UTF-8.
99    /// If this constraint is violated, undefined behavior results,
100    /// as the rest of Rust assumes that [`&str`]s are valid UTF-8.
101    #[inline]
102    pub unsafe fn key_str_unchecked(&self) -> &str {
103        std::str::from_utf8_unchecked(self.key())
104    }
105
106    /// The value held by the key, in bytes.
107    #[inline]
108    pub fn value(&self) -> &[u8] {
109        &self.0.value
110    }
111
112    /// The value held by the key, in string.
113    #[inline]
114    pub fn value_str(&self) -> Result<&str> {
115        std::str::from_utf8(self.value()).map_err(From::from)
116    }
117
118    /// The value held by the key, in bytes.
119    ///
120    /// # Safety
121    /// This function is unsafe because it does not check that the bytes of the value are valid UTF-8.
122    /// If this constraint is violated, undefined behavior results,
123    /// as the rest of Rust assumes that [`&str`]s are valid UTF-8.
124    #[inline]
125    pub unsafe fn value_str_unchecked(&self) -> &str {
126        std::str::from_utf8_unchecked(self.value())
127    }
128
129    /// Convert to key-value pair.
130    pub fn into_key_value(self) -> (Vec<u8>, Vec<u8>) {
131        (self.0.key, self.0.value)
132    }
133
134    /// The revision of last creation on this key.
135    #[inline]
136    pub const fn create_revision(&self) -> i64 {
137        self.0.create_revision
138    }
139
140    /// The revision of last modification on this key.
141    #[inline]
142    pub const fn mod_revision(&self) -> i64 {
143        self.0.mod_revision
144    }
145
146    /// The version of the key. A deletion resets
147    /// the version to zero and any modification of the key
148    /// increases its version.
149    #[inline]
150    pub const fn version(&self) -> i64 {
151        self.0.version
152    }
153
154    /// The ID of the lease that attached to key.
155    /// When the attached lease expires, the key will be deleted.
156    /// If lease is 0, then no lease is attached to the key.
157    #[inline]
158    pub const fn lease(&self) -> i64 {
159        self.0.lease
160    }
161}
162
163impl From<&PbKeyValue> for &KeyValue {
164    #[inline]
165    fn from(src: &PbKeyValue) -> Self {
166        unsafe { &*(src as *const _ as *const KeyValue) }
167    }
168}
169
170impl From<&mut PbKeyValue> for &mut KeyValue {
171    #[inline]
172    fn from(src: &mut PbKeyValue) -> Self {
173        unsafe { &mut *(src as *mut _ as *mut KeyValue) }
174    }
175}
176
177/// Get prefix end key of `key`.
178#[inline]
179fn get_prefix(key: &[u8]) -> Vec<u8> {
180    for (i, v) in key.iter().enumerate().rev() {
181        if *v < 0xFF {
182            let mut end = Vec::from(&key[..=i]);
183            end[i] = *v + 1;
184            return end;
185        }
186    }
187
188    // next prefix does not exist (e.g., 0xffff);
189    vec![0]
190}
191
192/// Key range builder.
193#[derive(Debug, Default, Clone)]
194struct KeyRange {
195    key: Vec<u8>,
196    range_end: Vec<u8>,
197    with_prefix: bool,
198    with_from_key: bool,
199    with_all_keys: bool,
200}
201
202impl KeyRange {
203    #[inline]
204    pub const fn new() -> Self {
205        KeyRange {
206            key: Vec::new(),
207            range_end: Vec::new(),
208            with_prefix: false,
209            with_from_key: false,
210            with_all_keys: false,
211        }
212    }
213
214    /// Sets key.
215    #[inline]
216    pub fn with_key(&mut self, key: impl Into<Vec<u8>>) {
217        self.key = key.into();
218    }
219
220    /// Specifies the range end.
221    /// `end_key` must be lexicographically greater than start key.
222    #[inline]
223    pub fn with_range(&mut self, end_key: impl Into<Vec<u8>>) {
224        self.range_end = end_key.into();
225        self.with_prefix = false;
226        self.with_from_key = false;
227        self.with_all_keys = false;
228    }
229
230    /// Sets all keys >= key.
231    #[inline]
232    pub fn with_from_key(&mut self) {
233        self.with_from_key = true;
234        self.with_prefix = false;
235        self.with_all_keys = false;
236    }
237
238    /// Sets all keys prefixed with key.
239    #[inline]
240    pub fn with_prefix(&mut self) {
241        self.with_prefix = true;
242        self.with_from_key = false;
243        self.with_all_keys = false;
244    }
245
246    /// Sets all keys.
247    #[inline]
248    pub fn with_all_keys(&mut self) {
249        self.with_all_keys = true;
250        self.with_prefix = false;
251        self.with_from_key = false;
252    }
253
254    /// Build the key and range end.
255    #[inline]
256    pub fn build(mut self) -> (Vec<u8>, Vec<u8>) {
257        if self.with_all_keys {
258            self.key = vec![b'\0'];
259            self.range_end = vec![b'\0'];
260        } else if self.with_from_key {
261            if self.key.is_empty() {
262                self.key = vec![b'\0'];
263            }
264            self.range_end = vec![b'\0'];
265        } else if self.with_prefix {
266            if self.key.is_empty() {
267                self.key = vec![b'\0'];
268                self.range_end = vec![b'\0'];
269            } else {
270                self.range_end = get_prefix(&self.key);
271            }
272        }
273
274        (self.key, self.range_end)
275    }
276}
277
278#[cfg(test)]
279mod tests {
280    use super::*;
281
282    #[test]
283    fn test_get_prefix() {
284        assert_eq!(get_prefix(b"foo1").as_slice(), b"foo2");
285        assert_eq!(get_prefix(b"\xFF").as_slice(), b"\0");
286        assert_eq!(get_prefix(b"foo\xFF").as_slice(), b"fop");
287    }
288}