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//!
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()
7988use crate :: Element ;
8089use crate :: Query ;
8190use 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///
101112pub 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
106117macro_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