dylanmckay / protocol Goto Github PK
View Code? Open in Web Editor NEWEasy protocol definitions in Rust
License: MIT License
Easy protocol definitions in Rust
License: MIT License
error[E0271]: type mismatch resolving `<i64 as std::convert::TryFrom<i8>>::Error == std::num::TryFromIntError`
--> ...\protocol-0.3.1\src\primitives\numerics.rs:102:6
|
102 | impl Integer for i64 { }
| ^^^^^^^ expected enum `std::convert::Infallible`, found struct `std::num::TryFromIntError`
|
= note: expected type `std::convert::Infallible`
found type `std::num::TryFromIntError`
Hello.
I wanted to write a small tool to calculate something distributed on a master with slaves and learn more about Rust on the way. Having a simple transport layer with the help of protocol
seemed like a good way. I'm using rustc 1.31.0 (abe02cefd 2018-12-04)
and am currently getting this error:
error[E0107]: wrong number of type arguments: expected 0, found 2
--> src/network.rs:4:10
|
4 | #[derive(Protocol, Debug, PartialEq)]
| ^^^^^^^^ 2 unexpected type arguments
I'm trying to use this on:
#[derive(Protocol, Debug, PartialEq)]
pub enum Message {
RequestRegistration,
Register(Registration),
Job(Job),
Result(Job, Result),
RequestStatus,
Status(Status),
}
Sadly the error is not very helpful in explaining what exactly I'm doing wrong but I highly suggest it has to do with Rust 2018, because the examples still use extern crate
and #[macro_use]
. Also there's no edition = "2018"
in the Cargo.toml
.
Any help on this is very appreciated. I don't think there's any other crate that can do what procotol
suggests it can do this easily.
Currently, there is the distinction between a Type
that can be serialised, and a Packet
that can be serialised. They both share almost the exact same definition.
It would be good to merge the two traits into one. This would allow connections to be build using primitives as packets, and also make everything more consistent.
Hello @dylanmckay,
do you plan on continuing work on this crate?
Seeing as there are several open issues and PRs, may I suggest adding me as a maintainer, or perhaps transferring ownership to my account @Feriixu?
In 19efbfa, a new #[protocol(name = "foo")]
attribute was introduced for enum variants.
We should support transmission of structures as field_name:field_value pairs so that fields may be added.
When this is done, we should also implement support for the #[protocol(name = "afd")]
for each field.
This panic line caused one of our production systems to crash when trying to decode messages on a noisy channel.
Now, I'm happy to fix this and submit a pull request but how? Because this is part of the derived parcel implementation, I'm not sure what the generated code ends up looking like or what can be returned here to replace the panic
I am having issues with getting the feature to use Uuid to work.
Cargo.toml:
[dependencies]
protocol-derive = "3.1.3"
protocol= { version = "3.1.3", features = ["uuid"] }
uuid="0.8.1"
Trying to compile something simple as
use uuid::Uuid;
use protocol_derive::Protocol;
#[derive(Protocol, Debug, Copy, Clone, PartialEq, Eq)]
pub struct Foo {
pub id: Uuid,
}
And then I got a compiler error:
#[derive(Protocol, Debug, Copy, Clone, PartialEq, Eq)]
| ^^^^^^^^ the trait `id::__impl_protocol___Parcel_FOR_Foo::protocol::HighLevel` is not implemented for `uuid::Uuid`
Am I missing something?
I am interested in retrieving the discriminant of the packet that I have received. Though it seams as this is not possible. And I only wish to ask if I have understood this correctly?
If we use the example from the documentation. What would hope would be possible would be to do the following:
loop {
if let Some(response) = connection.receive_packet().unwrap() {
println!("{:?}", response.discriminant());
break;
}
}
But to me it seams as the only way one can retrieve discriminators is through the enum that defines the protocol?
#[macro_use] extern crate protocol_derive;
#[macro_use] extern crate protocol;
#[derive(Protocol, Clone, Debug, PartialEq)]
pub struct Handshake;
#[derive(Protocol, Clone, Debug, PartialEq)]
pub struct Hello {
id: i64,
data: Vec<u8>,
}
#[derive(Protocol, Clone, Debug, PartialEq)]
pub struct Goodbye {
id: i64,
reason: String,
}
#[protocol(discriminant = "integer")]
#[derive(Protocol, Clone, Debug, PartialEq)]
#[repr(u16)]
pub enum PacketKind {
#[protocol(discriminator(0x00))]
Handshake(Handshake),
#[protocol(discriminator(0xaa))]
Hello(Hello),
#[protocol(discriminator(0xaf))]
Goodbye(Goodbye),
}
fn main() {
println!("Disc: {}", Packet::Handshake(Handshake)).discriminant());
}
In order to get the discriminant of message do I have to write my own function that checks the message type and return the appropriate discriminator by constructing a temporary object and extract it from the temporary object?
use protocol_derive;
use protocol::{ByteOrder, Enum, Parcel, Settings};
#[derive(Protocol, Clone, Debug, PartialEq)]
pub struct Handshake;
#[derive(Protocol, Clone, Debug, PartialEq)]
pub struct Hello {
id: i64,
data: Vec<u8>,
}
#[derive(Protocol, Clone, Debug, PartialEq)]
pub struct Goodbye {
id: i64,
reason: String,
}
#[protocol(discriminant = "integer")]
#[derive(Protocol, Clone, Debug, PartialEq)]
#[repr(u16)]
pub enum PacketKind {
#[protocol(discriminator(0x00))]
Handshake(Handshake),
#[protocol(discriminator(0xaa))]
Hello(Hello),
#[protocol(discriminator(0xaf))]
Goodbye(Goodbye),
}
impl PacketKind {
pub fn get_discriminator(&self) -> u16 {
match self {
PacketKind::Handshake(_) => {
PacketKind::Handshake(Handshake).discriminator()
},
PacketKind::Hello(_) => {
PacketKind::Hello(Hello {id: Default::default(), data: Default::default() }).discriminant()
},
PacketKind::GoodBye(_) => {
PacketKind::Goodbye(GoodBye {id: Default::default(), reason: "".to_string() }).discriminant()
},
}
It seam really weird that the library user would have to go through all this trouble to get the discriminant of the received package or am I missing something?
The protocol I am implementing has certain quirks. It is a opcode u16 based protocol, so first 2 bytes define the rest, but:
Some packets can be embebbed into other packets and depending on that, a CRC is added at the end or not.
Does protocol
has a easy way to map this? Is there a way that I can provide custom settings
or hints
?
Returns a Result<Option<P>, Error>
, but the docs are a bit terse
https://docs.rs/protocol/3.1.4/protocol/wire/stream/struct.Connection.html#method.receive_packet
Attempts to receive a packet
Ok(None)
mean here? Is it an error? If this is non-blocking, does it mean try again later?Hey,
I'm currently working on a Macho parser and couldn't figure out how to declare sized char arrays (char foo[16]
). I tried [u8; 16]
, with no luck.
Is that possible right now at all?
Thanks!
Hello , is it possible to set a fixed length for a string field ? I would need something like this :
#[derive(Protocol, Debug, Clone, PartialEq, Eq)]
pub struct DatFile {
#[protocol(fixed_lenght(8))]
game_version: String,
}
Right now if the raw bytes parse correctly, the next step in most applications is to validate (sanitize) the data. This being an additional step is a risk (programmer may forget about validation) and waste of resources (protocol
has to parse all fields before sanitation can run). It may also result in unnecessary allocations - let's say our protocol accepts Vec<_>
and someone sends us 8GB of data. protocol
will download, parse and allocate 8GB Vec
, which will be rejected by the next instruction like if vec.len() > 64 { return; }
.
I imagine code could look like this:
#[derive(Protocol)]
pub struct User {
pub name: String,
pub pub_key: [u8; 64],
}
impl User {
fn validate_name(name: String) -> bool { /* some code */ }
fn validate_pub_key(pub_key: [u8; 64]) -> bool { /* some code */ }
}
User::parse( // or `User::validate_from_raw_bytes`
&data,
&protocol::Settings::default()
).unwrap();
Alternatively, protocol
could generate trait, so we could have different ways of validating the same struct, and stateful validators:
#[derive(Protocol)]
pub struct User {
pub name: String,
pub pub_key: [u8; 64],
}
// protocol generates:
//
// trait UserValidate {
// fn validate_name(&mut self, name: String) -> bool;
// fn validate_pub_key(&mut self, pub_key: [u8; 64]) -> bool;
// }
struct UserBasicValidator;
impl UserValidate for UserBasicValidator {
fn validate_name(&mut self, name: String) -> bool { /* some code */ }
fn validate_pub_key(&mut self, pub_key: [u8; 64]) -> bool { /* some code */ }
}
User::parse(
&data,
&protocol::Settings::default(),
UserBasicValidator::new(),
).unwrap();
Platform: Windows
connection send_packet
function paniced when I move it into another std::thread::spawn
thread
I have tried to use this with a non_blocking socket and I get some weird error:
panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }'
protocol-3.1.3/src/wire/stream/transport/simple.rs:116:30
Is non blocking sockets supported?
Currently
#[derive(Protocol)]
enum Event<E: Event> {
// ...
}
will work.
However
#[derive(Protocol)]
enum Event<E> where E: Event {
// ...
}
does not. protocol-derive
only looks at the constraints on the generic types, it currently fails to look at the where clause constraints and add them to the new impl Parcel
.
Something like this needs to be done
diff --git a/protocol-derive/src/lib.rs b/protocol-derive/src/lib.rs
index 517c224..dfeda42 100644
--- a/protocol-derive/src/lib.rs
+++ b/protocol-derive/src/lib.rs
@@ -37,7 +37,7 @@ fn impl_parcel(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
/// Returns `(generics, where_predicates)`
fn build_generics(ast: &syn::DeriveInput) -> (Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>) {
let mut where_predicates = Vec::new();
- let generics: Vec<_> = ast.generics.params.iter().enumerate().map(|(i, p)| {
+ let generics: Vec<_> = ast.generics.type_params().enumerate().map(|(i, p)| {
match p {
syn::GenericParam::Type(t) => {
let (ident, bounds) = (&t.ident, &t.bounds);
NOTE: this if 1/3rd of a proper fix. A proper fix would also check generics.lifetimes()
and generics.const_params
and copy the constraints to the new impl
. Currently the patch would ignore lifetime parameters and break all traits with lifetime type parameters.
I am currently implementing a protocol that has 17 bytes or things that I don't care for now and then a 0 terminated string. It is datagram based, so the length of the packet is very clear from the start.
I am not the creator of the protocol, it has been around for 20 years or so.
Is there any way I can decode that string? What happens if there are bytes left to consume?
We could add impl Middleware for Option<M: Middleware>
.
Then piplines could be done line so
struct Pipeline {
encryption: Option<Encryption>,
compression: Option<Compression>,
}
fn handle(packet: _, pipeline: &mut Pipeline) {
match packet {
LoginSuccess => {
pipeline.encryption = Some(Encryption::new(..));
},
}
}
This would be required for protocols such as minecraft, which optionally enables encryption at login.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.