Flatbuffer multiple roots doesn't work as expected - rust

I'm evaluating/learning flatbuffers and I've written a schema and some basic code. The schema contains two root tables but when I try to convert a wrong root it doesn't fail. Is this expected behavior?
schema.fbs:
table Weapon {
name:string;
damage:short;
two_handed:bool;
}
root_type Weapon;
table Shield {
name:string;
damage:short;
}
root_type Shield;
main.rs:
use flatbuffers;
// import the generated code
#[allow(dead_code, unused_imports)]
#[path = "./schema_generated.rs"]
mod schema;
fn main() {
let mut sword_builder = flatbuffers::FlatBufferBuilder::new();
let sword_name = sword_builder.create_string("Sword");
let sword = schema::Weapon::create(
&mut sword_builder,
&schema::WeaponArgs {
name: Some(sword_name),
damage: 10,
two_handed: false,
},
);
sword_builder.finish(sword, None);
let sword_buffer = sword_builder.finished_data();
let mut shield_builder = flatbuffers::FlatBufferBuilder::new();
let shield_name = shield_builder.create_string("Shield");
let shield = schema::Weapon::create(
&mut shield_builder,
&schema::WeaponArgs {
name: Some(shield_name),
damage: 2,
two_handed: true,
},
);
shield_builder.finish(shield, None);
let shield_buffer = shield_builder.finished_data();
// Lets decode our buffers
let sword_decoded = flatbuffers::root::<schema::Weapon>(&sword_buffer).unwrap();
println!("{:#?}", sword_decoded);
let shield_decoded = flatbuffers::root::<schema::Shield>(&shield_buffer).unwrap();
println!("{:#?}", shield_decoded);
// This should fail:
let sword_decoded_failure = flatbuffers::root::<schema::Weapon>(&shield_buffer).unwrap();
println!("{:#?}", sword_decoded_failure);
}
output:
Weapon {
name: Some(
"Sword",
),
damage: 10,
two_handed: false,
}
Shield {
name: Some(
"Shield",
),
damage: 2,
}
Weapon {
name: Some(
"Shield",
),
damage: 2,
two_handed: true,
}
github link: https://github.com/ic3man5/fb_test
Documentation for root:
Gets the root of the Flatbuffer, verifying it first with default options. Note that verification is an experimental feature and may not be maximally performant or catch every error (though that is the goal). See the _unchecked variants for previous behavior.
I would expect it to be able to catch a basic error like this? If so I can see two work arounds, one to prepend a header in front of the bytes to identify the table or using a flatbuffer union (I don't want to do this).

Flatbuffers only allows one root type per schema and one instance of it per buffer. So your schema needs to change to reflect this.
As for there being no error, a verifier takes a binary buffer of bytes and checks that it can be safely accessed according to the current schema. There is no type information in the binary bytes, so if the bytes happen to be safely accessible by another schema, it may succeed. To force it to not succeed, you could add a file_identifier to your schema, which if the Rust verifier checks it, would cause it to fail for the wrong schema.

Related

How to return a single owned record with Diesel?

Actually I'm returing a cloned struct
pub fn matrix_first_or_create(&self, schema: String, symbol: String) -> RewardMatrix {
....
let rewards = reward_matrix
.filter(state.eq(schema.clone()))
.filter(turn_symbol.eq(symbol.clone()))
.limit(1)
.load::<RewardMatrix>(&self.connection)
.expect("Error loading posts");
if rewards.len() > 0 {
return rewards.get(0).unwrap().clone();
}
....
}
Is this the right way to handle a result in Diesel? Can I "extract" and own the first and only result from this query?
What you need here is the .first() method of the RunQueryDsl trait.
Here is an example of how it works:
let reward: RewardMatrix = reward_matrix
.filter(state.eq(schema.clone()))
.filter(turn_symbol.eq(symbol.clone()))
.first(&self.connection)?;
But if your query may not return that row, it’s also good to use the .optional() method of QueryResult:
let reward: Option<RewardMatrix> = reward_matrix
.filter(state.eq(schema.clone()))
.filter(turn_symbol.eq(symbol.clone()))
.first(&self.connection)
.optional()?;
load returns a simple owned Vec<RewardMatrix>, so any solution for getting an owned element from a Vec works here:
if let Some(reward) = rewards.into_iter().next() {
return reward;
}
but Diesel also provides better-suited alternatives like get_result and first that don’t involve Vec at all (combine with optional as recommended in the documentation):
let reward = reward_matrix
.filter(state.eq(&schema))
.filter(turn_symbol.eq(&symbol))
.first::<RewardMatrix>(&self.connection)
.optional()
.expect("Error loading posts");
if let Some(reward) = reward {
return reward;
}

is it possible using rust to generate jsx AST?

I'm not familiar with rust and trynna using swc to replace the babel
but I found #swc/core doesn't offer the api to generate code AST, so I want to write one using rust, is it possible to generate jsx ast?
Here is a good place to start: https://github.com/swc-project/swc/blob/main/crates/swc_ecma_parser/examples/typescript.rs
but link can get invalid so I also pasted the code:
use swc_common::{
self,
errors::{ColorConfig, Handler},
sync::Lrc,
FileName, SourceMap,
};
use swc_ecma_parser::{lexer::Lexer, Capturing, Parser, StringInput, Syntax};
fn main() {
let cm: Lrc<SourceMap> = Default::default();
let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(cm.clone()));
// Real usage
// let fm = cm
// .load_file(Path::new("test.js"))
// .expect("failed to load test.js");
let fm = cm.new_source_file(
FileName::Custom("test.js".into()),
"interface Foo {}".into(),
);
let lexer = Lexer::new(
Syntax::Typescript(Default::default()),
Default::default(),
StringInput::from(&*fm),
None,
);
let capturing = Capturing::new(lexer);
let mut parser = Parser::new_from(capturing);
for e in parser.take_errors() {
e.into_diagnostic(&handler).emit();
}
let _module = parser
.parse_typescript_module()
.map_err(|e| e.into_diagnostic(&handler).emit())
.expect("Failed to parse module.");
println!("Tokens: {:?}", parser.input().take());
}
I never really worked or cared about this. All it took was 5min of browsing the repository, all the resources are there but if you are new to rust, I recommend the rust book first.

Initialize Gstreamer's PadProbeId to a default value in Rust

I am familiar with Gstreamer but new to Rust,
TLDR; I want to be able to initialize PadProbeId to a default value before using it.
The details:
I have a Bin (containing audio + video encoders and hlssink).
I have been able to add this bin to the pipeline and it works fine.
The issue I have is the audio for the stream is optional and I want to do add_probe() only when audio is available. Below is a simplified version fo what I tried to implement
let mut audio_probe_id: PadProbeId;
let mut tee_audio_pad: Pad;
if media_info.audio_available {
// get encoded audio from the tee
tee_audio_pad = audio_tee.request_pad_simple("src_%u").unwrap();
audio_probe_id = tee_audio_pad.add_probe(gst::PadProbeType::BLOCK_DOWNSTREAM, |_pad, _info| {
gst::PadProbeReturn::Ok
}).unwrap();
// link the audio_tee.src to enc_bin ghost pad
let audio_sink_pad = enc_bin.static_pad("audio").unwrap();
tee_audio_pad.link(&audio_sink_pad).unwrap();
}
enc_bin.call_async(move |bin| {
bin.sync_state_with_parent().unwrap();
if media_info.audio_available {
tee_audio_pad.remove_probe(audio_probe_id);
}
}
However because of Rust compilers restriction to using uninitialized variables, it does not let me use audio_probe_id without initializing.
I tried to initialize it like this; let mut audio_probe_id: PadProbeId = PadProbeId(NonZeroU64(u64::MAX));. However compiler complains that it is a private field.
error[E0423]: cannot initialize a tuple struct which contains private fields
Thanks a lot for your help!
The rust way to have empty variables like this is to use Option, but in your case it would simpler to have a single conditional:
if media_info.audio_available {
// get encoded audio from the tee
let tee_audio_pad = audio_tee.request_pad_simple("src_%u").unwrap();
let audio_probe_id = tee_audio_pad.add_probe(gst::PadProbeType::BLOCK_DOWNSTREAM, |_pad, _info| {
gst::PadProbeReturn::Ok
}).unwrap();
// link the audio_tee.src to enc_bin ghost pad
let audio_sink_pad = enc_bin.static_pad("audio").unwrap();
tee_audio_pad.link(&audio_sink_pad).unwrap();
enc_bin.call_async(move |bin| {
bin.sync_state_with_parent().unwrap();
tee_audio_pad.remove_probe(audio_probe_id);
}
} else {
enc_bin.call_async(move |bin| {
bin.sync_state_with_parent().unwrap();
});
}

getting payload from a substrate event back in rust tests

i've created my first substrate project successful and the built pallet also works fine. Now i wanted to create tests for the flow and the provided functions.
My flow is to generate a random hash and store this hash associated to the sender of the transaction
let _sender = ensure_signed(origin)?;
let nonce = Nonce::get();
let _random_seed = <randomness_collective_flip::Module<T>>::random_seed();
let random_hash = (_random_seed, &_sender, nonce).using_encoded(T::Hashing::hash);
ensure!(!<Hashes<T>>::contains_key(random_hash), "This new id already exists");
let _now = <timestamp::Module<T>>::get();
let new_elem = HashElement {
id: random_hash,
parent: parent,
updated: _now,
created: _now
};
<Hashes<T>>::insert(random_hash, new_pid);
<HashOwner<T>>::insert(random_hash, &_sender);
Self::deposit_event(RawEvent::Created(random_hash, _sender));
Ok(())
works good so far, when now i want to test the flow with a written test, i want to check if the hash emitted in the Created event is also assigned in the HashOwner Map. For this i need to get the value out of the event back.
And this is my problem :D i'm not professional in rust and all examples i found are expecting all values emitted in the event like this:
// construct event that should be emitted in the method call directly above
let expected_event = TestEvent::generic_event(RawEvent::EmitInput(1, 32));
// iterate through array of `EventRecord`s
assert!(System::events().iter().any(|a| a.event == expected_event));
When debugging my written test:
assert_ok!(TemplateModule::create_hash(Origin::signed(1), None));
let events = System::events();
let lastEvent = events.last().unwrap();
let newHash = &lastEvent.event;
i see in VSCode that the values are available:
debug window of vs code
but i dont know how to get this Hash in a variable back... maybe this is only a one liner ... but my rust knowledge is damn too small :D
thank you for your help
Here's a somewhat generic example of how to parse and check events, if you only care about the last event that your module put in system and nothing else.
assert_eq!(
System::events()
// this gives you an EventRecord { event: ..., ...}
.into_iter()
// map into the inner `event`.
.map(|r| r.event)
// the inner event is like `OuterEvent::mdouleEvent(EventEnum)`. The name of the outer
// event comes from whatever you have placed in your `delc_event! {}` in test mocks.
.filter_map(|e| {
if let MetaEvent::templateModule(inner) = e {
Some(inner)
} else {
None
}
})
.last()
.unwrap(),
// RawEvent is defined and imported in the template.rs file.
// val1 and val2 are things that you want to assert against.
RawEvent::Created(val1, val2),
);
Indeed you can also omit the first map or do it in more compact ways, but I have done it like this so you can see it step by step.
Print the System::events(), this also helps.
I now got it from the response of kianenigma :)
I wanted to reuse the given data in the event:
let lastEvent = System::events()
// this gives you an EventRecord { event: ..., ...}
.into_iter()
// map into the inner `event`.
.map(|r| r.event)
// the inner event is like `OuterEvent::mdouleEvent(EventEnum)`. The name of the outer
// event comes from whatever you have placed in your `delc_event! {}` in test mocks.
.filter_map(|e| {
if let TestEvent::pid(inner) = e {
Some(inner)
} else {
None
}
})
.last()
.unwrap();
if let RawEvent::Created(newHash, initiatedAccount) = lastEvent {
// there are the values :D
}
this can maybe be written better but this helps me :)

Idiomatic rust way to properly parse Clap ArgMatches

I'm learning rust and trying to make a find like utility (yes another one), im using clap and trying to support command line and config file for the program's parameters(this has nothing to do with the clap yml file).
Im trying to parse the commands and if no commands were passed to the app, i will try to load them from a config file.
Now I don't know how to do this in an idiomatic way.
fn main() {
let matches = App::new("findx")
.version(crate_version!())
.author(crate_authors!())
.about("find + directory operations utility")
.arg(
Arg::with_name("paths")
...
)
.arg(
Arg::with_name("patterns")
...
)
.arg(
Arg::with_name("operation")
...
)
.get_matches();
let paths;
let patterns;
let operation;
if matches.is_present("patterns") && matches.is_present("operation") {
patterns = matches.values_of("patterns").unwrap().collect();
paths = matches.values_of("paths").unwrap_or(clap::Values<&str>{"./"}).collect(); // this doesn't work
operation = match matches.value_of("operation").unwrap() { // I dont like this
"Append" => Operation::Append,
"Prepend" => Operation::Prepend,
"Rename" => Operation::Rename,
_ => {
print!("Operation unsupported");
process::exit(1);
}
};
}else if Path::new("findx.yml").is_file(){
//TODO: try load from config file
}else{
eprintln!("Command line parameters or findx.yml file must be provided");
process::exit(1);
}
if let Err(e) = findx::run(Config {
paths: paths,
patterns: patterns,
operation: operation,
}) {
eprintln!("Application error: {}", e);
process::exit(1);
}
}
There is an idiomatic way to extract Option and Result types values to the same scope, i mean all examples that i have read, uses match or if let Some(x) to consume the x value inside the scope of the pattern matching, but I need to assign the value to a variable.
Can someone help me with this, or point me to the right direction?
Best Regards
Personally I see nothing wrong with using the match statements and folding it or placing it in another function. But if you want to remove it there are many options.
There is the ability to use the .default_value_if() method which is impl for clap::Arg and have a different default value depending on which match arm is matched.
From the clap documentation
//sets value of arg "other" to "default" if value of "--opt" is "special"
let m = App::new("prog")
.arg(Arg::with_name("opt")
.takes_value(true)
.long("opt"))
.arg(Arg::with_name("other")
.long("other")
.default_value_if("opt", Some("special"), "default"))
.get_matches_from(vec![
"prog", "--opt", "special"
]);
assert_eq!(m.value_of("other"), Some("default"));
In addition you can add a validator to your operation OR convert your valid operation values into flags.
Here's an example converting your match arm values into individual flags (smaller example for clarity).
extern crate clap;
use clap::{Arg,App};
fn command_line_interface<'a>() -> clap::ArgMatches<'a> {
//Sets the command line interface of the program.
App::new("something")
.version("0.1")
.arg(Arg::with_name("rename")
.help("renames something")
.short("r")
.long("rename"))
.arg(Arg::with_name("prepend")
.help("prepends something")
.short("p")
.long("prepend"))
.arg(Arg::with_name("append")
.help("appends something")
.short("a")
.long("append"))
.get_matches()
}
#[derive(Debug)]
enum Operation {
Rename,
Append,
Prepend,
}
fn main() {
let matches = command_line_interface();
let operation = if matches.is_present("rename") {
Operation::Rename
} else if matches.is_present("prepend"){
Operation::Prepend
} else {
//DEFAULT
Operation::Append
};
println!("Value of operation is {:?}",operation);
}
I hope this helps!
EDIT:
You can also use Subcommands with your specific operations. It all depends on what you want to interface to be like.
let app_m = App::new("git")
.subcommand(SubCommand::with_name("clone"))
.subcommand(SubCommand::with_name("push"))
.subcommand(SubCommand::with_name("commit"))
.get_matches();
match app_m.subcommand() {
("clone", Some(sub_m)) => {}, // clone was used
("push", Some(sub_m)) => {}, // push was used
("commit", Some(sub_m)) => {}, // commit was used
_ => {}, // Either no subcommand or one not tested for...
}

Resources