#[cfg(feature = "pub-response-field")]
pub(crate) mod pb;
#[cfg(not(feature = "pub-response-field"))]
mod pb;
pub mod auth;
pub mod cluster;
pub mod election;
pub mod kv;
pub mod lease;
pub mod lock;
pub mod maintenance;
pub mod watch;
use crate::error::Result;
use pb::etcdserverpb::ResponseHeader as PbResponseHeader;
use pb::mvccpb::KeyValue as PbKeyValue;
#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct ResponseHeader(PbResponseHeader);
impl ResponseHeader {
#[inline]
pub(crate) const fn new(header: PbResponseHeader) -> Self {
Self(header)
}
#[inline]
pub const fn cluster_id(&self) -> u64 {
self.0.cluster_id
}
#[inline]
pub const fn member_id(&self) -> u64 {
self.0.member_id
}
#[inline]
pub const fn revision(&self) -> i64 {
self.0.revision
}
#[inline]
pub const fn raft_term(&self) -> u64 {
self.0.raft_term
}
}
impl From<&PbResponseHeader> for &ResponseHeader {
#[inline]
fn from(src: &PbResponseHeader) -> Self {
unsafe { &*(src as *const _ as *const ResponseHeader) }
}
}
#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct KeyValue(PbKeyValue);
impl KeyValue {
#[inline]
pub(crate) const fn new(kv: PbKeyValue) -> Self {
Self(kv)
}
#[inline]
pub fn key(&self) -> &[u8] {
&self.0.key
}
#[inline]
pub fn key_str(&self) -> Result<&str> {
std::str::from_utf8(self.key()).map_err(From::from)
}
#[inline]
pub unsafe fn key_str_unchecked(&self) -> &str {
std::str::from_utf8_unchecked(self.key())
}
#[inline]
pub fn value(&self) -> &[u8] {
&self.0.value
}
#[inline]
pub fn value_str(&self) -> Result<&str> {
std::str::from_utf8(self.value()).map_err(From::from)
}
#[inline]
pub unsafe fn value_str_unchecked(&self) -> &str {
std::str::from_utf8_unchecked(self.value())
}
pub fn into_key_value(self) -> (Vec<u8>, Vec<u8>) {
(self.0.key, self.0.value)
}
#[inline]
pub const fn create_revision(&self) -> i64 {
self.0.create_revision
}
#[inline]
pub const fn mod_revision(&self) -> i64 {
self.0.mod_revision
}
#[inline]
pub const fn version(&self) -> i64 {
self.0.version
}
#[inline]
pub const fn lease(&self) -> i64 {
self.0.lease
}
}
impl From<&PbKeyValue> for &KeyValue {
#[inline]
fn from(src: &PbKeyValue) -> Self {
unsafe { &*(src as *const _ as *const KeyValue) }
}
}
impl From<&mut PbKeyValue> for &mut KeyValue {
#[inline]
fn from(src: &mut PbKeyValue) -> Self {
unsafe { &mut *(src as *mut _ as *mut KeyValue) }
}
}
#[inline]
fn get_prefix(key: &[u8]) -> Vec<u8> {
for (i, v) in key.iter().enumerate().rev() {
if *v < 0xFF {
let mut end = Vec::from(&key[..=i]);
end[i] = *v + 1;
return end;
}
}
vec![0]
}
#[derive(Debug, Default, Clone)]
struct KeyRange {
key: Vec<u8>,
range_end: Vec<u8>,
with_prefix: bool,
with_from_key: bool,
with_all_keys: bool,
}
impl KeyRange {
#[inline]
pub const fn new() -> Self {
KeyRange {
key: Vec::new(),
range_end: Vec::new(),
with_prefix: false,
with_from_key: false,
with_all_keys: false,
}
}
#[inline]
pub fn with_key(&mut self, key: impl Into<Vec<u8>>) {
self.key = key.into();
}
#[inline]
pub fn with_range(&mut self, end_key: impl Into<Vec<u8>>) {
self.range_end = end_key.into();
self.with_prefix = false;
self.with_from_key = false;
self.with_all_keys = false;
}
#[inline]
pub fn with_from_key(&mut self) {
self.with_from_key = true;
self.with_prefix = false;
self.with_all_keys = false;
}
#[inline]
pub fn with_prefix(&mut self) {
self.with_prefix = true;
self.with_from_key = false;
self.with_all_keys = false;
}
#[inline]
pub fn with_all_keys(&mut self) {
self.with_all_keys = true;
self.with_prefix = false;
self.with_from_key = false;
}
#[inline]
pub fn build(mut self) -> (Vec<u8>, Vec<u8>) {
if self.with_all_keys {
self.key = vec![b'\0'];
self.range_end = vec![b'\0'];
} else if self.with_from_key {
if self.key.is_empty() {
self.key = vec![b'\0'];
}
self.range_end = vec![b'\0'];
} else if self.with_prefix {
if self.key.is_empty() {
self.key = vec![b'\0'];
self.range_end = vec![b'\0'];
} else {
self.range_end = get_prefix(&self.key);
}
}
(self.key, self.range_end)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_prefix() {
assert_eq!(get_prefix(b"foo1").as_slice(), b"foo2");
assert_eq!(get_prefix(b"\xFF").as_slice(), b"\0");
assert_eq!(get_prefix(b"foo\xFF").as_slice(), b"fop");
}
}