Skip to content

Commit

Permalink
Add cbor support
Browse files Browse the repository at this point in the history
  • Loading branch information
Semyon Uchvatov committed Nov 28, 2024
1 parent b240904 commit 8d6a19d
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 8 deletions.
21 changes: 13 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ stdlib = [
"dep:chacha20poly1305",
"dep:charset",
"dep:convert_case",
"dep:ciborium",
"dep:cidr-utils",
"dep:community-id",
"dep:crypto_secretbox",
Expand Down Expand Up @@ -129,6 +130,7 @@ bytes = { version = "1", default-features = false, optional = true }
charset = { version = "0.1", optional = true }
chrono = { version = "0.4", default-features = false, features = ["clock", "serde", "wasmbind"], optional = true }
chrono-tz = { version = "0.10", default-features = false, optional = true }
ciborium = { version = "0.2.2", default-features = false, optional = true }
cidr-utils = { version = "0.6", optional = true }
csv = { version = "1", optional = true }
clap = { version = "4", features = ["derive"], optional = true }
Expand Down
2 changes: 2 additions & 0 deletions LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ chacha20poly1305,https://github.com/RustCrypto/AEADs/tree/master/chacha20poly130
charset,https://github.com/hsivonen/charset,Apache-2.0 OR MIT,Henri Sivonen <hsivonen@hsivonen.fi>
chrono,https://github.com/chronotope/chrono,MIT OR Apache-2.0,The chrono Authors
chrono-tz,https://github.com/chronotope/chrono-tz,MIT OR Apache-2.0,The chrono-tz Authors
ciborium,https://github.com/enarx/ciborium,Apache-2.0,Nathaniel McCallum <npmccallum@profian.com>
cidr,https://github.com/stbuehler/rust-cidr,MIT,Stefan Bühler <stbuehler@web.de>
cidr-utils,https://github.com/magiclen/cidr-utils,MIT,Magic Len <len@magiclen.org>
cipher,https://github.com/RustCrypto/traits,MIT OR Apache-2.0,RustCrypto Developers
Expand Down Expand Up @@ -102,6 +103,7 @@ generic-array,https://github.com/fizyk20/generic-array,MIT,"Bartłomiej Kamińsk
getrandom,https://github.com/rust-random/getrandom,MIT OR Apache-2.0,The Rand Project Developers
gimli,https://github.com/gimli-rs/gimli,MIT OR Apache-2.0,The gimli Authors
grok,https://github.com/daschl/grok,Apache-2.0,Michael Nitschinger <michael@nitschinger.at>
half,https://github.com/starkat99/half-rs,MIT OR Apache-2.0,Kathryn Long <squeeself@gmail.com>
hashbrown,https://github.com/rust-lang/hashbrown,MIT OR Apache-2.0,Amanieu d'Antras <amanieu@gmail.com>
heck,https://github.com/withoutboats/heck,MIT OR Apache-2.0,The heck Authors
heck,https://github.com/withoutboats/heck,MIT OR Apache-2.0,Without Boats <woboats@gmail.com>
Expand Down
1 change: 1 addition & 0 deletions changelog.d/1152.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `parse_cbor` function
3 changes: 3 additions & 0 deletions src/stdlib/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ cfg_if::cfg_if! {
mod parse_aws_cloudwatch_log_subscription_message;
mod parse_aws_vpc_flow_log;
mod parse_cef;
mod parse_cbor;
mod parse_common_log;
mod parse_csv;
mod parse_duration;
Expand Down Expand Up @@ -316,6 +317,7 @@ cfg_if::cfg_if! {
pub use parse_aws_alb_log::ParseAwsAlbLog;
pub use parse_aws_cloudwatch_log_subscription_message::ParseAwsCloudWatchLogSubscriptionMessage;
pub use parse_aws_vpc_flow_log::ParseAwsVpcFlowLog;
pub use parse_cbor::ParseCbor;
pub use parse_cef::ParseCef;
pub use parse_common_log::ParseCommonLog;
pub use parse_csv::ParseCsv;
Expand Down Expand Up @@ -500,6 +502,7 @@ pub fn all() -> Vec<Box<dyn Function>> {
Box::new(ParseAwsAlbLog),
Box::new(ParseAwsCloudWatchLogSubscriptionMessage),
Box::new(ParseAwsVpcFlowLog),
Box::new(ParseCbor),
Box::new(ParseCef),
Box::new(ParseCommonLog),
Box::new(ParseCsv),
Expand Down
128 changes: 128 additions & 0 deletions src/stdlib/parse_cbor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use crate::compiler::prelude::*;
use ciborium::de::from_reader;
use zstd::zstd_safe::WriteBuf;

fn parse_cbor(value: Value) -> Resolved {
let bytes = value.try_bytes()?;
let value = from_reader(bytes.as_slice()).map_err(|e| format!("unable to parse cbor: {e}"))?;
Ok(value)
}

#[derive(Clone, Copy, Debug)]
pub struct ParseCbor;

impl Function for ParseCbor {
fn identifier(&self) -> &'static str {
"parse_cbor"
}

fn summary(&self) -> &'static str {
"parse a string to a JSON type"
}

fn usage(&self) -> &'static str {
indoc! {"
Parses the provided `value` as CBOR.
Only JSON types are returned. If you need to convert a `string` into a `timestamp`,
consider the `parse_timestamp` function.
"}
}

fn parameters(&self) -> &'static [Parameter] {
&[Parameter {
keyword: "value",
kind: kind::BYTES,
required: true,
}]
}

fn examples(&self) -> &'static [Example] {
&[Example {
title: "object",
source: r#"parse_cbor!(decode_base64!("oWVmaWVsZGV2YWx1ZQ=="))"#,
result: Ok(r#"{ "field": "value" }"#),
}]
}

fn compile(
&self,
_state: &state::TypeState,
_ctx: &mut FunctionCompileContext,
arguments: ArgumentList,
) -> Compiled {
let value = arguments.required("value");
Ok(ParseCborFn { value }.as_expr())
}
}

#[derive(Debug, Clone)]
struct ParseCborFn {
value: Box<dyn Expression>,
}

impl FunctionExpression for ParseCborFn {
fn resolve(&self, ctx: &mut Context) -> Resolved {
let value = self.value.resolve(ctx)?;
parse_cbor(value)
}

fn type_def(&self, _: &state::TypeState) -> TypeDef {
type_def()
}
}

fn inner_kind() -> Kind {
Kind::null()
| Kind::bytes()
| Kind::integer()
| Kind::float()
| Kind::boolean()
| Kind::array(Collection::any())
| Kind::object(Collection::any())
}

fn type_def() -> TypeDef {
TypeDef::bytes()
.fallible()
.or_boolean()
.or_integer()
.or_float()
.add_null()
.or_array(Collection::from_unknown(inner_kind()))
.or_object(Collection::from_unknown(inner_kind()))
}

#[cfg(test)]
mod tests {
use super::*;
use crate::value;
use nom::AsBytes;
use std::env;
use std::fs;
use std::path::PathBuf;

fn test_data_dir() -> PathBuf {
PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("tests/data/cbor")
}

fn read_cbor_file(cbor_bin_message_path: &str) -> Vec<u8> {
fs::read(test_data_dir().join(cbor_bin_message_path)).unwrap()
}

test_function![
parse_cbor => ParseCbor;

parses {
args: func_args![ value: value!(read_cbor_file("simple.cbor").as_bytes()) ],
want: Ok(value!({ field: "value" })),
tdef: type_def(),
}

complex_cbor {
args: func_args![ value: value!(read_cbor_file("complex.cbor").as_bytes()) ],
want: Ok(value!({ object: {string: "value", number: 42, array: ["hello", "world"], boolean: false} })),
tdef: type_def(),
}
];
}
1 change: 1 addition & 0 deletions tests/data/cbor/complex.cbor
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�fobject�fstringevaluefnumber*earray�ehelloeworldgboolean�
1 change: 1 addition & 0 deletions tests/data/cbor/simple.cbor
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�efieldevalue

0 comments on commit 8d6a19d

Please sign in to comment.