diff --git a/Cargo.lock b/Cargo.lock index 2dc8ae14b6..4328de40d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2408,6 +2408,48 @@ dependencies = [ "indexmap 2.0.0", ] +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.33", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.3" @@ -3437,6 +3479,12 @@ dependencies = [ "event-listener 2.5.3", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -5062,6 +5110,7 @@ dependencies = [ "const_format", "hex", "lazy_static", + "phf", "rand 0.8.5", "serde", "uhlc", diff --git a/Cargo.toml b/Cargo.toml index 9af42deeae..9c73ae62ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,11 +110,12 @@ libloading = "0.8" log = "0.4.17" lz4_flex = "0.11" nix = { version = "0.27", features = ["fs"] } -num_cpus = "1.15.0" +num_cpus = "1.16.0" ordered-float = "4.1.1" panic-message = "0.3.0" paste = "1.0.12" petgraph = "0.6.3" +phf = { version = "0.11.2", features = ["macros"] } pnet = "0.34" pnet_datalink = "0.34" proc-macro2 = "1.0.51" diff --git a/commons/zenoh-codec/src/core/encoding.rs b/commons/zenoh-codec/src/core/encoding.rs index 478bcf1cd8..0895396198 100644 --- a/commons/zenoh-codec/src/core/encoding.rs +++ b/commons/zenoh-codec/src/core/encoding.rs @@ -17,7 +17,7 @@ use zenoh_buffers::{ reader::{DidntRead, Reader}, writer::{DidntWrite, Writer}, }; -use zenoh_protocol::core::Encoding; +use zenoh_protocol::core::{Encoding, EncodingPrefix}; impl LCodec<&Encoding> for Zenoh080 { fn w_len(self, x: &Encoding) -> usize { @@ -32,8 +32,8 @@ where type Output = Result<(), DidntWrite>; fn write(self, writer: &mut W, x: &Encoding) -> Self::Output { - let zodec = Zenoh080Bounded::::new(); - zodec.write(&mut *writer, *x.prefix() as u8)?; + let zodec = Zenoh080Bounded::::new(); + zodec.write(&mut *writer, x.prefix())?; zodec.write(&mut *writer, x.suffix())?; Ok(()) } @@ -46,8 +46,8 @@ where type Error = DidntRead; fn read(self, reader: &mut R) -> Result { - let zodec = Zenoh080Bounded::::new(); - let prefix: u8 = zodec.read(&mut *reader)?; + let zodec = Zenoh080Bounded::::new(); + let prefix: EncodingPrefix = zodec.read(&mut *reader)?; let suffix: String = zodec.read(&mut *reader)?; let encoding = Encoding::new(prefix, suffix).map_err(|_| DidntRead)?; Ok(encoding) diff --git a/commons/zenoh-protocol/Cargo.toml b/commons/zenoh-protocol/Cargo.toml index 07c11cb2fc..7c1a49c5fd 100644 --- a/commons/zenoh-protocol/Cargo.toml +++ b/commons/zenoh-protocol/Cargo.toml @@ -44,6 +44,7 @@ complete_n = [] const_format = { workspace = true } hex = { workspace = true, features = ["alloc"] } rand = { workspace = true, features = ["alloc", "getrandom"], optional = true } +phf = { workspace = true } serde = { workspace = true, features = ["alloc"] } uhlc = { workspace = true, default-features = false } uuid = { workspace = true } # Needs a getrandom::getrandom() custom implementation on embedded (in root crate) diff --git a/commons/zenoh-protocol/src/core/cowstr.rs b/commons/zenoh-protocol/src/core/cowstr.rs index 33dac4524f..209d020f40 100644 --- a/commons/zenoh-protocol/src/core/cowstr.rs +++ b/commons/zenoh-protocol/src/core/cowstr.rs @@ -21,7 +21,7 @@ enum CowStrInner<'a> { } pub struct CowStr<'a>(CowStrInner<'a>); impl<'a> CowStr<'a> { - pub(crate) fn borrowed(s: &'a str) -> Self { + pub(crate) const fn borrowed(s: &'a str) -> Self { Self(CowStrInner::Borrowed(s)) } pub fn as_str(&self) -> &str { diff --git a/commons/zenoh-protocol/src/core/encoding.rs b/commons/zenoh-protocol/src/core/encoding.rs index f202b8e79c..defbf767b6 100644 --- a/commons/zenoh-protocol/src/core/encoding.rs +++ b/commons/zenoh-protocol/src/core/encoding.rs @@ -13,131 +13,135 @@ // use crate::core::CowStr; use alloc::{borrow::Cow, string::String}; -use core::{ - convert::TryFrom, - fmt::{self, Debug}, - mem, -}; -use zenoh_result::{bail, zerror, ZError, ZResult}; +use core::fmt::{self, Debug}; +use zenoh_result::{bail, ZResult}; -mod consts { - pub(super) const MIMES: [&str; 21] = [ - /* 0 */ "", - /* 1 */ "application/octet-stream", - /* 2 */ "application/custom", // non iana standard - /* 3 */ "text/plain", - /* 4 */ "application/properties", // non iana standard - /* 5 */ "application/json", // if not readable from casual users - /* 6 */ "application/sql", - /* 7 */ "application/integer", // non iana standard - /* 8 */ "application/float", // non iana standard - /* 9 */ - "application/xml", // if not readable from casual users (RFC 3023, sec 3) - /* 10 */ "application/xhtml+xml", - /* 11 */ "application/x-www-form-urlencoded", - /* 12 */ "text/json", // non iana standard - if readable from casual users - /* 13 */ "text/html", - /* 14 */ "text/xml", // if readable from casual users (RFC 3023, section 3) - /* 15 */ "text/css", - /* 16 */ "text/csv", - /* 17 */ "text/javascript", - /* 18 */ "image/jpeg", - /* 19 */ "image/png", - /* 20 */ "image/gif", - ]; -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum KnownEncoding { - Empty = 0, - AppOctetStream = 1, - AppCustom = 2, - TextPlain = 3, - AppProperties = 4, - AppJson = 5, - AppSql = 6, - AppInteger = 7, - AppFloat = 8, - AppXml = 9, - AppXhtmlXml = 10, - AppXWwwFormUrlencoded = 11, - TextJson = 12, - TextHtml = 13, - TextXml = 14, - TextCss = 15, - TextCsv = 16, - TextJavascript = 17, - ImageJpeg = 18, - ImagePng = 19, - ImageGif = 20, -} - -impl From for u8 { - fn from(val: KnownEncoding) -> Self { - val as u8 - } -} - -impl From for &str { - fn from(val: KnownEncoding) -> Self { - consts::MIMES[u8::from(val) as usize] - } -} - -impl TryFrom for KnownEncoding { - type Error = ZError; - fn try_from(value: u8) -> Result { - if value < consts::MIMES.len() as u8 + 1 { - Ok(unsafe { mem::transmute(value) }) - } else { - Err(zerror!("Unknown encoding")) - } - } -} - -impl AsRef for KnownEncoding { - fn as_ref(&self) -> &str { - consts::MIMES[u8::from(*self) as usize] - } -} +pub type EncodingPrefix = u8; /// The encoding of a zenoh `zenoh::Value`. /// /// A zenoh encoding is a HTTP Mime type represented, for wire efficiency, /// as an integer prefix (that maps to a string) and a string suffix. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum Encoding { - Exact(KnownEncoding), - WithSuffix(KnownEncoding, CowStr<'static>), +pub struct Encoding { + prefix: EncodingPrefix, + suffix: CowStr<'static>, +} + +pub mod prefix { + use crate::core::encoding::EncodingPrefix; + use phf::phf_ordered_map; + + /// Prefixes from 0 to 63 are reserved by Zenoh + /// Users are free to use any prefix from 64 to 255 + pub const EMPTY: EncodingPrefix = 0; + pub const APP_OCTET_STREAM: EncodingPrefix = 1; + pub const APP_CUSTOM: EncodingPrefix = 2; + pub const TEXT_PLAIN: EncodingPrefix = 3; + pub const APP_PROPERTIES: EncodingPrefix = 4; + pub const APP_JSON: EncodingPrefix = 5; + pub const APP_SQL: EncodingPrefix = 6; + pub const APP_INTEGER: EncodingPrefix = 7; + pub const APP_FLOAT: EncodingPrefix = 8; + pub const APP_XML: EncodingPrefix = 9; + pub const APP_XHTML_XML: EncodingPrefix = 10; + pub const APP_XWWW_FORM_URLENCODED: EncodingPrefix = 11; + pub const TEXT_JSON: EncodingPrefix = 12; + pub const TEXT_HTML: EncodingPrefix = 13; + pub const TEXT_XML: EncodingPrefix = 14; + pub const TEXT_CSS: EncodingPrefix = 15; + pub const TEXT_CSV: EncodingPrefix = 16; + pub const TEXT_JAVASCRIPT: EncodingPrefix = 17; + pub const IMAGE_JPEG: EncodingPrefix = 18; + pub const IMAGE_PNG: EncodingPrefix = 19; + pub const IMAGE_GIF: EncodingPrefix = 20; + + // A perfect hashmap for fast lookup of prefixes + pub(super) const KNOWN: phf::OrderedMap = phf_ordered_map! { + 0u8 => "", + 1u8 => "application/octet-stream", + 2u8 => "application/custom", // non iana standard + 3u8 => "text/plain", + 4u8 => "application/properties", // non iana standard + 5u8 => "application/json", // if not readable from casual users + 6u8 => "application/sql", + 7u8 => "application/integer", // non iana standard + 8u8 => "application/float", // non iana standard + 9u8 => "application/xml", // if not readable from casual users (RFC 3023, sec 3) + 10u8 => "application/xhtml+xml", + 11u8 => "application/x-www-form-urlencoded", + 12u8 => "text/json", // non iana standard - if readable from casual users + 13u8 => "text/html", + 14u8 => "text/xml", // if readable from casual users (RFC 3023, section 3) + 15u8 => "text/css", + 16u8 => "text/csv", + 17u8 => "text/javascript", + 18u8 => "image/jpeg", + 19u8 => "image/png", + 20u8 => "image/gif", + }; } impl Encoding { - pub fn new(prefix: u8, suffix: IntoCowStr) -> ZResult + /// The encoding is empty. It is equivalent to not being defined. + pub const EMPTY: Encoding = Encoding::exact(prefix::EMPTY); + pub const APP_OCTET_STREAM: Encoding = Encoding::exact(prefix::APP_OCTET_STREAM); + pub const APP_CUSTOM: Encoding = Encoding::exact(prefix::APP_CUSTOM); + pub const TEXT_PLAIN: Encoding = Encoding::exact(prefix::TEXT_PLAIN); + pub const APP_PROPERTIES: Encoding = Encoding::exact(prefix::APP_PROPERTIES); + pub const APP_JSON: Encoding = Encoding::exact(prefix::APP_JSON); + pub const APP_SQL: Encoding = Encoding::exact(prefix::APP_SQL); + pub const APP_INTEGER: Encoding = Encoding::exact(prefix::APP_INTEGER); + pub const APP_FLOAT: Encoding = Encoding::exact(prefix::APP_FLOAT); + pub const APP_XML: Encoding = Encoding::exact(prefix::APP_XML); + pub const APP_XHTML_XML: Encoding = Encoding::exact(prefix::APP_XHTML_XML); + pub const APP_XWWW_FORM_URLENCODED: Encoding = + Encoding::exact(prefix::APP_XWWW_FORM_URLENCODED); + pub const TEXT_JSON: Encoding = Encoding::exact(prefix::TEXT_JSON); + pub const TEXT_HTML: Encoding = Encoding::exact(prefix::TEXT_HTML); + pub const TEXT_XML: Encoding = Encoding::exact(prefix::TEXT_XML); + pub const TEXT_CSS: Encoding = Encoding::exact(prefix::TEXT_CSS); + pub const TEXT_CSV: Encoding = Encoding::exact(prefix::TEXT_CSV); + pub const TEXT_JAVASCRIPT: Encoding = Encoding::exact(prefix::TEXT_JAVASCRIPT); + pub const IMAGE_JPEG: Encoding = Encoding::exact(prefix::IMAGE_JPEG); + pub const IMAGE_PNG: Encoding = Encoding::exact(prefix::IMAGE_PNG); + pub const IMAGE_GIF: Encoding = Encoding::exact(prefix::IMAGE_GIF); + + pub const fn exact(prefix: EncodingPrefix) -> Self { + Self { + prefix, + suffix: CowStr::borrowed(""), + } + } + + /// Returns a new [`Encoding`] object. + /// This method will return an error when the suffix is longer than 255 characters. + pub fn new(prefix: EncodingPrefix, suffix: IntoCowStr) -> ZResult where IntoCowStr: Into> + AsRef, { - let prefix = KnownEncoding::try_from(prefix)?; - let suffix = suffix.into(); - if suffix.as_bytes().len() > u8::MAX as usize { + let suffix: Cow<'static, str> = suffix.into(); + if suffix.as_bytes().len() > EncodingPrefix::MAX as usize { bail!("Suffix length is limited to 255 characters") } - if suffix.as_ref().is_empty() { - Ok(Encoding::Exact(prefix)) - } else { - Ok(Encoding::WithSuffix(prefix, suffix.into())) - } + Ok(Self { + prefix, + suffix: suffix.into(), + }) } /// Sets the suffix of this encoding. - pub fn with_suffix(self, suffix: IntoCowStr) -> ZResult + /// This method will return an error when the suffix is longer than 255 characters. + pub fn with_suffix(mut self, suffix: IntoCowStr) -> ZResult where IntoCowStr: Into> + AsRef, { - match self { - Encoding::Exact(e) => Encoding::new(e as u8, suffix), - Encoding::WithSuffix(e, s) => Encoding::new(e as u8, s + suffix.as_ref()), + let s: Cow<'static, str> = suffix.into(); + if s.as_bytes().len() > u8::MAX as usize { + bail!("Suffix length is limited to 255 characters") } + self.suffix = (self.suffix + s.as_ref()).into(); + Ok(self) } pub fn as_ref<'a, T>(&'a self) -> T @@ -147,7 +151,7 @@ impl Encoding { self.into() } - /// Returns `true`if the string representation of this encoding starts with + /// Returns `true` if the string representation of this encoding starts with /// the string representation of ther given encoding. pub fn starts_with(&self, with: T) -> bool where @@ -157,111 +161,89 @@ impl Encoding { self.prefix() == with.prefix() && self.suffix().starts_with(with.suffix()) } - pub const fn prefix(&self) -> &KnownEncoding { - match self { - Encoding::Exact(e) | Encoding::WithSuffix(e, _) => e, - } + pub const fn prefix(&self) -> EncodingPrefix { + self.prefix } pub fn suffix(&self) -> &str { - match self { - Encoding::Exact(_) => "", - Encoding::WithSuffix(_, s) => s.as_ref(), - } + self.suffix.as_str() } } -impl Encoding { - pub const EMPTY: Encoding = Encoding::Exact(KnownEncoding::Empty); - pub const APP_OCTET_STREAM: Encoding = Encoding::Exact(KnownEncoding::AppOctetStream); - pub const APP_CUSTOM: Encoding = Encoding::Exact(KnownEncoding::AppCustom); - pub const TEXT_PLAIN: Encoding = Encoding::Exact(KnownEncoding::TextPlain); - pub const APP_PROPERTIES: Encoding = Encoding::Exact(KnownEncoding::AppProperties); - pub const APP_JSON: Encoding = Encoding::Exact(KnownEncoding::AppJson); - pub const APP_SQL: Encoding = Encoding::Exact(KnownEncoding::AppSql); - pub const APP_INTEGER: Encoding = Encoding::Exact(KnownEncoding::AppInteger); - pub const APP_FLOAT: Encoding = Encoding::Exact(KnownEncoding::AppFloat); - pub const APP_XML: Encoding = Encoding::Exact(KnownEncoding::AppXml); - pub const APP_XHTML_XML: Encoding = Encoding::Exact(KnownEncoding::AppXhtmlXml); - pub const APP_XWWW_FORM_URLENCODED: Encoding = - Encoding::Exact(KnownEncoding::AppXWwwFormUrlencoded); - pub const TEXT_JSON: Encoding = Encoding::Exact(KnownEncoding::TextJson); - pub const TEXT_HTML: Encoding = Encoding::Exact(KnownEncoding::TextHtml); - pub const TEXT_XML: Encoding = Encoding::Exact(KnownEncoding::TextXml); - pub const TEXT_CSS: Encoding = Encoding::Exact(KnownEncoding::TextCss); - pub const TEXT_CSV: Encoding = Encoding::Exact(KnownEncoding::TextCsv); - pub const TEXT_JAVASCRIPT: Encoding = Encoding::Exact(KnownEncoding::TextJavascript); - pub const IMAGE_JPEG: Encoding = Encoding::Exact(KnownEncoding::ImageJpeg); - pub const IMAGE_PNG: Encoding = Encoding::Exact(KnownEncoding::ImagePng); - pub const IMAGE_GIF: Encoding = Encoding::Exact(KnownEncoding::ImageGif); +impl From<&EncodingPrefix> for Encoding { + fn from(e: &EncodingPrefix) -> Encoding { + Encoding::exact(*e) + } +} + +impl From for Encoding { + fn from(e: EncodingPrefix) -> Encoding { + Encoding::exact(e) + } } impl fmt::Display for Encoding { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Encoding::Exact(e) => f.write_str(e.as_ref()), - Encoding::WithSuffix(e, s) => { - f.write_str(e.as_ref())?; - f.write_str(s) - } + match prefix::KNOWN.get(&self.prefix) { + Some(s) => write!(f, "{}", s)?, + None => write!(f, "Unknown({})", self.prefix)?, } + write!(f, "{}", self.suffix.as_str()) } } -impl From<&'static str> for Encoding { - fn from(s: &'static str) -> Self { - for (i, v) in consts::MIMES.iter().enumerate().skip(1) { +impl TryFrom<&'static str> for Encoding { + type Error = zenoh_result::Error; + + fn try_from(s: &'static str) -> Result { + for (k, v) in prefix::KNOWN.entries().skip(1) { if let Some(suffix) = s.strip_prefix(v) { + let e = Encoding::exact(*k); if suffix.is_empty() { - return Encoding::Exact(unsafe { mem::transmute(i as u8) }); + return Ok(e); } else { - return Encoding::WithSuffix(unsafe { mem::transmute(i as u8) }, suffix.into()); + return e.with_suffix(suffix); } } } + + let e = Encoding::EMPTY; if s.is_empty() { - Encoding::Exact(KnownEncoding::Empty) + Ok(e) } else { - Encoding::WithSuffix(KnownEncoding::Empty, s.into()) + e.with_suffix(s) } } } -impl From for Encoding { - fn from(mut s: String) -> Self { - for (i, v) in consts::MIMES.iter().enumerate().skip(1) { +impl TryFrom for Encoding { + type Error = zenoh_result::Error; + + fn try_from(mut s: String) -> Result { + for (k, v) in prefix::KNOWN.entries().skip(1) { if s.starts_with(v) { s.replace_range(..v.len(), ""); + let e = Encoding::exact(*k); if s.is_empty() { - return Encoding::Exact(unsafe { mem::transmute(i as u8) }); + return Ok(e); } else { - return Encoding::WithSuffix(unsafe { mem::transmute(i as u8) }, s.into()); + return e.with_suffix(s); } } } + + let e = Encoding::EMPTY; if s.is_empty() { - Encoding::Exact(KnownEncoding::Empty) + Ok(e) } else { - Encoding::WithSuffix(KnownEncoding::Empty, s.into()) + e.with_suffix(s) } } } -impl From<&KnownEncoding> for Encoding { - fn from(e: &KnownEncoding) -> Encoding { - Encoding::Exact(*e) - } -} - -impl From for Encoding { - fn from(e: KnownEncoding) -> Encoding { - Encoding::Exact(e) - } -} - impl Default for Encoding { fn default() -> Self { - KnownEncoding::Empty.into() + Encoding::EMPTY } } @@ -278,7 +260,7 @@ impl Encoding { let mut rng = rand::thread_rng(); - let prefix: u8 = rng.gen_range(0..20); + let prefix: EncodingPrefix = rng.gen(); let suffix: String = if rng.gen_bool(0.5) { let len = rng.gen_range(MIN..MAX); Alphanumeric.sample_string(&mut rng, len) diff --git a/commons/zenoh-protocol/src/core/mod.rs b/commons/zenoh-protocol/src/core/mod.rs index 2547034c44..48868b2034 100644 --- a/commons/zenoh-protocol/src/core/mod.rs +++ b/commons/zenoh-protocol/src/core/mod.rs @@ -43,7 +43,7 @@ pub use wire_expr::*; mod cowstr; pub use cowstr::CowStr; mod encoding; -pub use encoding::{Encoding, KnownEncoding}; +pub use encoding::{prefix, Encoding, EncodingPrefix}; pub mod locator; pub use locator::*; diff --git a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs index 0c6eb4357b..aa64ca6bd1 100644 --- a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs +++ b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs @@ -76,7 +76,7 @@ async fn main() { println!("Data updates are accessible through HTML5 SSE at http://:8000/{key}"); loop { publisher - .put(Value::from(value).encoding(KnownEncoding::TextPlain.into())) + .put(Value::from(value).encoding(Encoding::TEXT_PLAIN)) .res() .await .unwrap(); diff --git a/plugins/zenoh-plugin-rest/src/lib.rs b/plugins/zenoh-plugin-rest/src/lib.rs index 6f4e80f4eb..0edcbf4cb7 100644 --- a/plugins/zenoh-plugin-rest/src/lib.rs +++ b/plugins/zenoh-plugin-rest/src/lib.rs @@ -49,19 +49,19 @@ const RAW_KEY: &str = "_raw"; fn value_to_json(value: Value) -> String { // @TODO: transcode to JSON when implemented in Value match &value.encoding { - p if p.starts_with(KnownEncoding::TextPlain) - || p.starts_with(KnownEncoding::AppXWwwFormUrlencoded) => + p if p.starts_with(Encoding::TEXT_PLAIN) + || p.starts_with(Encoding::APP_XWWW_FORM_URLENCODED) => { // convert to Json string for special characters escaping serde_json::json!(value.to_string()).to_string() } - p if p.starts_with(KnownEncoding::AppProperties) => { + p if p.starts_with(Encoding::APP_PROPERTIES) => { // convert to Json string for special characters escaping serde_json::json!(*Properties::from(value.to_string())).to_string() } - p if p.starts_with(KnownEncoding::AppJson) - || p.starts_with(KnownEncoding::AppInteger) - || p.starts_with(KnownEncoding::AppFloat) => + p if p.starts_with(Encoding::APP_JSON) + || p.starts_with(Encoding::APP_INTEGER) + || p.starts_with(Encoding::APP_FLOAT) => { value.to_string() } @@ -402,10 +402,19 @@ async fn query(mut req: Request<(Arc, String)>) -> tide::Result match Encoding::try_from(m.to_string()) { + Ok(e) => e, + Err(e) => { + return Ok(response( + StatusCode::BadRequest, + "text/plain", + &e.to_string(), + )); + } + }, + None => Encoding::default(), + }; query = query.with_value(Value::from(body).encoding(encoding)); } match query.res().await { @@ -441,10 +450,20 @@ async fn write(mut req: Request<(Arc, String)>) -> tide::Result match Encoding::try_from(m.to_string()) { + Ok(e) => e, + Err(e) => { + return Ok(response( + StatusCode::BadRequest, + "text/plain", + &e.to_string(), + )); + } + }, + None => Encoding::default(), + }; // @TODO: Define the right congestion control value match req diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs index 115ed1e8d9..6a05a79bd2 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs @@ -688,15 +688,15 @@ fn serialize_update(update: &Update) -> String { } fn construct_update(data: String) -> Update { - let result: (String, String, String, Vec<&[u8]>) = serde_json::from_str(&data).unwrap(); + let result: (String, String, String, Vec<&[u8]>) = serde_json::from_str(&data).unwrap(); // @TODO: remove the unwrap() let mut payload = ZBuf::default(); for slice in result.3 { payload.push_zslice(slice.to_vec().into()); } - let value = Value::new(payload).encoding(Encoding::from(result.2)); + let value = Value::new(payload).encoding(Encoding::try_from(result.2).unwrap()); // @TODO: remove the unwrap() let data = StoredData { value, - timestamp: Timestamp::from_str(&result.1).unwrap(), + timestamp: Timestamp::from_str(&result.1).unwrap(), // @TODO: remove the unwrap() }; let kind = if result.0.eq(&(SampleKind::Put).to_string()) { SampleKind::Put diff --git a/zenoh/src/admin.rs b/zenoh/src/admin.rs index 8cdf638af5..9ff1bb3878 100644 --- a/zenoh/src/admin.rs +++ b/zenoh/src/admin.rs @@ -26,7 +26,7 @@ use std::{ }; use zenoh_core::SyncResolve; use zenoh_protocol::{ - core::{Encoding, KnownEncoding, WireExpr}, + core::{Encoding, WireExpr}, network::NetworkMessage, }; use zenoh_transport::{ @@ -145,7 +145,7 @@ impl TransportMulticastEventHandler for Handler { let expr = WireExpr::from(&(*KE_PREFIX / own_zid / *KE_TRANSPORT_UNICAST / zid)) .to_owned(); let info = DataInfo { - encoding: Some(Encoding::Exact(KnownEncoding::AppJson)), + encoding: Some(Encoding::APP_JSON), ..Default::default() }; self.session.handle_data( @@ -191,7 +191,7 @@ impl TransportPeerEventHandler for PeerHandler { let mut s = DefaultHasher::new(); link.hash(&mut s); let info = DataInfo { - encoding: Some(Encoding::Exact(KnownEncoding::AppJson)), + encoding: Some(Encoding::APP_JSON), ..Default::default() }; self.session.handle_data( diff --git a/zenoh/src/net/runtime/adminspace.rs b/zenoh/src/net/runtime/adminspace.rs index f6fb13e76e..15880a6510 100644 --- a/zenoh/src/net/runtime/adminspace.rs +++ b/zenoh/src/net/runtime/adminspace.rs @@ -30,9 +30,11 @@ use std::sync::Mutex; use zenoh_buffers::buffer::SplitBuffer; use zenoh_config::{ConfigValidator, ValidatedMap, WhatAmI}; use zenoh_plugin_trait::{PluginControl, PluginStatus}; -use zenoh_protocol::core::key_expr::keyexpr; use zenoh_protocol::{ - core::{key_expr::OwnedKeyExpr, ExprId, KnownEncoding, WireExpr, ZenohId, EMPTY_EXPR_ID}, + core::{ + key_expr::{keyexpr, OwnedKeyExpr}, + Encoding, ExprId, WireExpr, ZenohId, EMPTY_EXPR_ID, + }, network::{ declare::{queryable::ext::QueryableInfo, subscriber::ext::SubscriberInfo}, ext, Declare, DeclareBody, DeclareQueryable, DeclareSubscriber, Push, Request, Response, @@ -560,8 +562,7 @@ fn router_data(context: &AdminContext, query: Query) { if let Err(e) = query .reply(Ok(Sample::new( reply_key, - Value::from(json.to_string().as_bytes().to_vec()) - .encoding(KnownEncoding::AppJson.into()), + Value::from(json.to_string().as_bytes().to_vec()).encoding(Encoding::APP_JSON), ))) .res() { @@ -595,7 +596,7 @@ zenoh_build{{version="{}"}} 1 if let Err(e) = query .reply(Ok(Sample::new( reply_key, - Value::from(metrics.as_bytes().to_vec()).encoding(KnownEncoding::TextPlain.into()), + Value::from(metrics.as_bytes().to_vec()).encoding(Encoding::TEXT_PLAIN), ))) .res() { @@ -620,7 +621,7 @@ fn routers_linkstate_data(context: &AdminContext, query: Query) { .as_bytes() .to_vec(), ) - .encoding(KnownEncoding::TextPlain.into()), + .encoding(Encoding::TEXT_PLAIN), ))) .res() { @@ -645,7 +646,7 @@ fn peers_linkstate_data(context: &AdminContext, query: Query) { .as_bytes() .to_vec(), ) - .encoding(KnownEncoding::TextPlain.into()), + .encoding(Encoding::TEXT_PLAIN), ))) .res() { @@ -719,7 +720,7 @@ fn plugins_status(context: &AdminContext, query: Query) { if let Err(e) = query .reply(Ok(Sample::new( key_expr, - Value::from(plugin.path()).encoding(KnownEncoding::AppJson.into()), + Value::from(plugin.path()).encoding(Encoding::TEXT_PLAIN), ))) .res() { @@ -746,7 +747,7 @@ fn plugins_status(context: &AdminContext, query: Query) { if let Ok(key_expr) = KeyExpr::try_from(response.key) { if let Err(e) = query.reply(Ok(Sample::new( key_expr, - Value::from(response.value).encoding(KnownEncoding::AppJson.into()), + Value::from(response.value).encoding(Encoding::TEXT_PLAIN), ))) .res() { diff --git a/zenoh/src/prelude.rs b/zenoh/src/prelude.rs index 36a841d1ef..1a408ed014 100644 --- a/zenoh/src/prelude.rs +++ b/zenoh/src/prelude.rs @@ -43,7 +43,7 @@ pub(crate) mod common { pub use crate::value::Value; /// The encoding of a zenoh `Value`. - pub use zenoh_protocol::core::{Encoding, KnownEncoding}; + pub use zenoh_protocol::core::{prefix as EncodingPrefix, Encoding}; pub use crate::query::ConsolidationMode; #[zenoh_macros::unstable] diff --git a/zenoh/src/value.rs b/zenoh/src/value.rs index 849cfd57d5..94e28f9aaf 100644 --- a/zenoh/src/value.rs +++ b/zenoh/src/value.rs @@ -24,7 +24,7 @@ use zenoh_collections::Properties; use zenoh_result::ZError; use crate::buffers::ZBuf; -use crate::prelude::{Encoding, KnownEncoding, Sample, SplitBuffer}; +use crate::prelude::{Encoding, EncodingPrefix, Sample, SplitBuffer}; #[cfg(feature = "shared-memory")] use zenoh_shm::SharedMemoryBuf; @@ -43,7 +43,7 @@ impl Value { pub fn new(payload: ZBuf) -> Self { Value { payload, - encoding: KnownEncoding::AppOctetStream.into(), + encoding: Encoding::APP_OCTET_STREAM, } } @@ -51,7 +51,7 @@ impl Value { pub fn empty() -> Self { Value { payload: ZBuf::empty(), - encoding: KnownEncoding::AppOctetStream.into(), + encoding: Encoding::EMPTY, } } @@ -93,7 +93,7 @@ impl From> for Value { fn from(smb: Arc) -> Self { Value { payload: smb.into(), - encoding: KnownEncoding::AppOctetStream.into(), + encoding: Encoding::APP_OCTET_STREAM, } } } @@ -111,7 +111,7 @@ impl From for Value { fn from(smb: SharedMemoryBuf) -> Self { Value { payload: smb.into(), - encoding: KnownEncoding::AppOctetStream.into(), + encoding: Encoding::APP_OCTET_STREAM, } } } @@ -121,7 +121,7 @@ impl From for Value { fn from(buf: ZBuf) -> Self { Value { payload: buf, - encoding: KnownEncoding::AppOctetStream.into(), + encoding: Encoding::APP_OCTET_STREAM, } } } @@ -131,7 +131,7 @@ impl TryFrom<&Value> for ZBuf { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppOctetStream => Ok(v.payload.clone()), + EncodingPrefix::APP_OCTET_STREAM => Ok(v.payload.clone()), unexpected => Err(zerror!( "{:?} can not be converted into Cow<'a, [u8]>", unexpected @@ -159,7 +159,7 @@ impl<'a> TryFrom<&'a Value> for Cow<'a, [u8]> { fn try_from(v: &'a Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppOctetStream => Ok(v.payload.contiguous()), + EncodingPrefix::APP_OCTET_STREAM => Ok(v.payload.contiguous()), unexpected => Err(zerror!( "{:?} can not be converted into Cow<'a, [u8]>", unexpected @@ -179,7 +179,7 @@ impl TryFrom<&Value> for Vec { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppOctetStream => Ok(v.payload.contiguous().to_vec()), + EncodingPrefix::APP_OCTET_STREAM => Ok(v.payload.contiguous().to_vec()), unexpected => Err(zerror!( "{:?} can not be converted into Vec", unexpected @@ -201,7 +201,7 @@ impl From for Value { fn from(s: String) -> Self { Value { payload: ZBuf::from(s.into_bytes()), - encoding: KnownEncoding::TextPlain.into(), + encoding: Encoding::TEXT_PLAIN, } } } @@ -210,7 +210,7 @@ impl From<&str> for Value { fn from(s: &str) -> Self { Value { payload: ZBuf::from(Vec::::from(s)), - encoding: KnownEncoding::TextPlain.into(), + encoding: Encoding::TEXT_PLAIN, } } } @@ -220,7 +220,7 @@ impl TryFrom<&Value> for String { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::TextPlain => { + EncodingPrefix::TEXT_PLAIN => { String::from_utf8(v.payload.contiguous().to_vec()).map_err(|e| zerror!("{}", e)) } unexpected => Err(zerror!("{:?} can not be converted into String", unexpected)), @@ -248,7 +248,7 @@ impl From for Value { fn from(i: i64) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -258,7 +258,7 @@ impl TryFrom<&Value> for i64 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -280,7 +280,7 @@ impl From for Value { fn from(i: i32) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -290,7 +290,7 @@ impl TryFrom<&Value> for i32 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -312,7 +312,7 @@ impl From for Value { fn from(i: i16) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -322,7 +322,7 @@ impl TryFrom<&Value> for i16 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -344,7 +344,7 @@ impl From for Value { fn from(i: i8) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -354,7 +354,7 @@ impl TryFrom<&Value> for i8 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -376,7 +376,7 @@ impl From for Value { fn from(i: isize) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -386,7 +386,7 @@ impl TryFrom<&Value> for isize { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -408,7 +408,7 @@ impl From for Value { fn from(i: u64) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -418,7 +418,7 @@ impl TryFrom<&Value> for u64 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -440,7 +440,7 @@ impl From for Value { fn from(i: u32) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -450,7 +450,7 @@ impl TryFrom<&Value> for u32 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -472,7 +472,7 @@ impl From for Value { fn from(i: u16) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -482,7 +482,7 @@ impl TryFrom<&Value> for u16 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -504,7 +504,7 @@ impl From for Value { fn from(i: u8) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -514,7 +514,7 @@ impl TryFrom<&Value> for u8 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -536,7 +536,7 @@ impl From for Value { fn from(i: usize) -> Self { Value { payload: ZBuf::from(Vec::::from(i.to_string())), - encoding: KnownEncoding::AppInteger.into(), + encoding: Encoding::APP_INTEGER, } } } @@ -546,7 +546,7 @@ impl TryFrom<&Value> for usize { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppInteger => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_INTEGER => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -568,7 +568,7 @@ impl From for Value { fn from(f: f64) -> Self { Value { payload: ZBuf::from(Vec::::from(f.to_string())), - encoding: KnownEncoding::AppFloat.into(), + encoding: Encoding::APP_FLOAT, } } } @@ -578,7 +578,7 @@ impl TryFrom<&Value> for f64 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppFloat => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_FLOAT => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -600,7 +600,7 @@ impl From for Value { fn from(f: f32) -> Self { Value { payload: ZBuf::from(Vec::::from(f.to_string())), - encoding: KnownEncoding::AppFloat.into(), + encoding: Encoding::APP_FLOAT, } } } @@ -610,7 +610,7 @@ impl TryFrom<&Value> for f32 { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppFloat => std::str::from_utf8(&v.payload.contiguous()) + EncodingPrefix::APP_FLOAT => std::str::from_utf8(&v.payload.contiguous()) .map_err(|e| zerror!("{}", e))? .parse() .map_err(|e| zerror!("{}", e)), @@ -632,7 +632,7 @@ impl From<&serde_json::Value> for Value { fn from(json: &serde_json::Value) -> Self { Value { payload: ZBuf::from(Vec::::from(json.to_string())), - encoding: KnownEncoding::AppJson.into(), + encoding: Encoding::APP_JSON, } } } @@ -648,7 +648,7 @@ impl TryFrom<&Value> for serde_json::Value { fn try_from(v: &Value) -> Result { match v.encoding.prefix() { - KnownEncoding::AppJson | KnownEncoding::TextJson => { + EncodingPrefix::APP_JSON | EncodingPrefix::TEXT_JSON => { let r = serde::Deserialize::deserialize(&mut serde_json::Deserializer::from_slice( &v.payload.contiguous(), )); @@ -675,7 +675,7 @@ impl From for Value { fn from(p: Properties) -> Self { Value { payload: ZBuf::from(Vec::::from(p.to_string())), - encoding: KnownEncoding::AppProperties.into(), + encoding: Encoding::APP_PROPERTIES, } } } @@ -684,8 +684,8 @@ impl TryFrom<&Value> for Properties { type Error = ZError; fn try_from(v: &Value) -> Result { - match *v.encoding.prefix() { - KnownEncoding::AppProperties => Ok(Properties::from( + match v.encoding.prefix() { + EncodingPrefix::APP_PROPERTIES => Ok(Properties::from( std::str::from_utf8(&v.payload.contiguous()).map_err(|e| zerror!("{}", e))?, )), unexpected => Err(zerror!(