Skip to content

Commit 458ade8

Browse files
committed
Add RawString type
1 parent d89a920 commit 458ade8

File tree

3 files changed

+120
-24
lines changed

3 files changed

+120
-24
lines changed

src/aio.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
//! # Asynchronous database connections
1919
//!
20-
//! This module provides sync interfaces for database connections. There are two versions:
20+
//! This module provides async interfaces for database connections. There are two versions:
2121
//! - The [`Connection`]: a connection to the database over Skyhash/TCP
2222
//! - The [`TlsConnection`]: a connection to the database over Skyhash/TLS
2323
//!

src/lib.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,10 @@
5757
//! let mut con = Connection::new("127.0.0.1", 2003)?;
5858
//! let query = Query::from("heya");
5959
//! let res = con.run_simple_query(&query)?;
60-
//! assert_eq!(res, Response::Item(Element::Binstr(Vec::from("HEY"))));
60+
//! assert_eq!(res, Response::Item(Element::Str("HEY".to_owned())));
6161
//! Ok(())
6262
//! }
6363
//! ```
64-
//!
65-
//! **And why was our string a [`Vec`]?**
66-
//! That's because the server sends a binary string with arbitrary bytes. The returned value may
67-
//! or may not be unicode, and this depends on the data type you set for your table.
68-
//!
6964
//! Way to go — you're all set! Now go ahead and run more advanced queries!
7065
//!
7166
//! ## Going advanced
@@ -268,7 +263,7 @@ impl<'a> ConnectionBuilder<'a> {
268263
/// ```
269264
macro_rules! query {
270265
($($arg:expr),+) => {
271-
skytable::Query::new()$(.arg($arg))*
266+
$crate::Query::new()$(.arg($arg))*
272267
};
273268
}
274269

@@ -291,6 +286,9 @@ macro_rules! query {
291286
/// let q2 = Query::from(vec!["mset", "x", "100", "y", "200", "z", "300"]);
292287
/// let q3 = Query::from("get").arg("x");
293288
/// ```
289+
/// **Important:** You should use the [`RawString`](types::RawString) type if you're willing to directly add things like
290+
/// `Vec<u8>` to your query.
291+
///
294292
/// Finally, queries can also be created by taking references. For example:
295293
/// ```
296294
/// use skytable::Query;
@@ -339,8 +337,7 @@ impl Query {
339337
arg.push_into_query(&mut self);
340338
self
341339
}
342-
pub(in crate) fn _push_arg(&mut self, arg: impl IntoSkyhashBytes) {
343-
let arg = arg.as_string();
340+
pub(in crate) fn _push_arg(&mut self, arg: Vec<u8>) {
344341
if arg.is_empty() {
345342
panic!("Argument cannot be empty")
346343
}
@@ -351,7 +348,7 @@ impl Query {
351348
// add the LF char
352349
self.data.push(b'\n');
353350
// Add the data itself, which is `arg`
354-
self.data.extend(arg.into_bytes());
351+
self.data.extend(arg);
355352
self.data.push(b'\n'); // add the LF char
356353
self.size_count += 1;
357354
}
@@ -375,8 +372,8 @@ impl Query {
375372
U: IntoSkyhashBytes,
376373
{
377374
v1.get_iter().zip(v2.get_iter()).for_each(|(a, b)| {
378-
self.push(a.as_string());
379-
self.push(b.as_string());
375+
self.push(a.to_bytes());
376+
self.push(b.to_bytes());
380377
});
381378
self
382379
}

src/types.rs

Lines changed: 110 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,30 @@
2222
//!
2323
//!
2424
//! ## Implementing a Skyhash serializable type
25-
//! If you have an object that can be turned into a [`String`] or a sequence of [`String`] objects, then
25+
//! If you have an object that can be turned into a [`Vec<u8>`] or a sequence of [`Vec<u8>`] objects, then
2626
//! your type can be serialized by Skyhash (this might change in the future with more types being supported).
27+
//!
28+
//! ## Use [`RawString`]!
29+
//!
30+
//! It is very important that you use [`RawString`] for types like String or `Vec<u8>`, else
31+
//! all the elements will be individually serialized! See the [`RawString`] docs for more
32+
//! information.
33+
//!
2734
//! Here is a simple example:
2835
//! ```
2936
//! use skytable::actions::Actions;
30-
//! use skytable::types::{IntoSkyhashAction, IntoSkyhashBytes, GetIterator};
37+
//! use skytable::types::{IntoSkyhashAction, IntoSkyhashBytes, GetIterator, RawString};
3138
//! use skytable::Query;
3239
//!
3340
//! /// Our custom element that adds "cool" to the end of every string when serialized
3441
//! struct CoolString(String);
3542
//!
3643
//! impl IntoSkyhashBytes for CoolString {
37-
//! fn as_string(&self) -> String {
44+
//! fn to_bytes(&self) -> Vec<u8> {
3845
//! let mut st = self.0.to_string();
3946
//! // add cool
4047
//! st.push_str("cool");
41-
//! st
48+
//! st.into_bytes()
4249
//! }
4350
//! }
4451
//!
@@ -47,7 +54,9 @@
4754
//!
4855
//! impl IntoSkyhashAction for CoolStringCollection {
4956
//! fn push_into_query(&self, query: &mut Query) {
50-
//! self.0.iter().for_each(|item| query.push(item.as_string()));
57+
//! self.0.iter().for_each(|item| {
58+
//! query.push(RawString(item.to_bytes()))
59+
//! });
5160
//! }
5261
//! fn incr_len_by(&self) -> usize {
5362
//! self.0.len()
@@ -79,6 +88,8 @@
7988
use crate::Element;
8089
use crate::Query;
8190
use crate::RespCode;
91+
use core::ops::Deref;
92+
use core::ops::DerefMut;
8293

8394
/// Anything that implements this trait can be turned into a [`String`]. This trait is implemented
8495
/// for most primitive types by default using [`std`]'s [`ToString`] trait.
@@ -92,23 +103,23 @@ use crate::RespCode;
92103
/// struct MyStringWrapper(String);
93104
///
94105
/// impl IntoSkyhashBytes for MyStringWrapper {
95-
/// fn as_string(&self) -> String {
96-
/// self.0.to_string()
106+
/// fn to_bytes(&self) -> Vec<u8> {
107+
/// self.0.as_bytes().to_owned()
97108
/// }
98109
/// }
99110
/// ```
100111
///
101112
pub trait IntoSkyhashBytes: Send + Sync {
102113
/// Turn `Self` into a [`String`]
103-
fn as_string(&self) -> String;
114+
fn to_bytes(&self) -> Vec<u8>;
104115
}
105116

106117
macro_rules! impl_skyhash_bytes {
107118
($($ty:ty),*) => {
108119
$(
109120
impl IntoSkyhashBytes for $ty {
110-
fn as_string(&self) -> String {
111-
self.to_string()
121+
fn to_bytes(&self) -> Vec<u8> {
122+
self.to_string().into_bytes()
112123
}
113124
}
114125
)*
@@ -161,7 +172,7 @@ where
161172
T: IntoSkyhashBytes,
162173
{
163174
fn push_into_query(&self, q: &mut Query) {
164-
q._push_arg(self.as_string());
175+
q._push_arg(self.to_bytes());
165176
}
166177
fn incr_len_by(&self) -> usize {
167178
1
@@ -311,3 +322,91 @@ pub enum FlatElement {
311322
/// An unsigned integer
312323
UnsignedInt(u64),
313324
}
325+
326+
/// A raw binary string
327+
///
328+
/// Use this type when you need to directly send binary data instead of converting
329+
/// each element into a Skyhash binary string. For example, if you:
330+
///
331+
/// ```
332+
/// use skytable::query;
333+
/// let myvec: Vec<u8> = vec![1, 2, 3, 4];
334+
/// let x = query!("SET", "mybindata", myvec);
335+
/// ```
336+
///
337+
/// **⚠️⚠️⚠️ You're not sending a binary/unicode string!** Instead, what you're actually running is:
338+
/// ```
339+
/// use skytable::query;
340+
/// let x = query!("SET", "mybindata", 1, 2, 3, 4);
341+
/// ```
342+
///
343+
/// This type allows you to _escape_ this so that you can send already assembled
344+
/// binary data like this:
345+
/// ```
346+
/// use skytable::query;
347+
/// use skytable::types::RawString;
348+
///
349+
/// let mut mybin = RawString::from(vec![1, 2, 3, 4]);
350+
/// let x = query!("SET", "mybindata", mybin);
351+
///
352+
/// ```
353+
/// You can also use the RawString as a standard `Vec<u8>`:
354+
/// ```
355+
/// use skytable::types::RawString;
356+
/// let mut mybin = RawString::new();
357+
/// mybin.push(1);
358+
/// mybin.push(2);
359+
/// mybin.push(3);
360+
///
361+
/// assert_eq!(mybin, vec![1, 2, 3]);
362+
/// ```
363+
#[derive(Debug, PartialEq)]
364+
pub struct RawString(pub Vec<u8>);
365+
366+
impl Default for RawString {
367+
fn default() -> Self {
368+
Self::new()
369+
}
370+
}
371+
372+
impl RawString {
373+
pub fn with_capacity(cap: usize) -> Self {
374+
Self(Vec::with_capacity(cap))
375+
}
376+
pub fn new() -> Self {
377+
Self(Vec::new())
378+
}
379+
}
380+
381+
impl Deref for RawString {
382+
type Target = Vec<u8>;
383+
fn deref(&self) -> &Self::Target {
384+
&self.0
385+
}
386+
}
387+
388+
impl DerefMut for RawString {
389+
fn deref_mut(&mut self) -> &mut Vec<u8> {
390+
&mut self.0
391+
}
392+
}
393+
394+
impl From<Vec<u8>> for RawString {
395+
fn from(oth: Vec<u8>) -> Self {
396+
Self(oth)
397+
}
398+
}
399+
400+
impl PartialEq<Vec<u8>> for RawString {
401+
fn eq(&self, oth: &Vec<u8>) -> bool {
402+
self.0.eq(oth)
403+
}
404+
}
405+
406+
impl Eq for RawString {}
407+
408+
impl IntoSkyhashBytes for RawString {
409+
fn to_bytes(&self) -> Vec<u8> {
410+
self.0.to_owned()
411+
}
412+
}

0 commit comments

Comments
 (0)