only-cliches / NoProto

Flexible, Fast & Compact Serialization with RPC
MIT License
373 stars 14 forks source link

version 0.10 #17

Closed janjaapbos closed 2 years ago

janjaapbos commented 2 years ago

It looks like that RPC is done differently in 0.10, but is not quite implemented yet. Is that correct?

Could you summarize the principle differences between 0.10 and 0.9.6? It is difficult to see in the code, because of the move of the old source tree.

Thank you!

only-cliches commented 2 years ago

Yeah, the RPC is being completely redone in 0.10.0, as well as most of the other aspects of the library. And 0.10.0 isn't ready to go and won't be for at least a few more weeks.

The biggest difference between the older version and what I'm working on now is the schema format support and everything that follows from that.

First off, it's important to note that I'm quite a bit off from having 0.10.0 release ready to go, so these changes are still in flux and what I'm saying here might not represent the final release.

In 0.9.6 and many versions before, you could do a JSON style schema. In 0.10.0, I'm working to support a schema that is nearly identical to Rust syntax for data types with some additions. The current working schema format is in this file:

https://github.com/only-cliches/NoProto/blob/master/idl.graphql (I know it has a graphql extension, ignore that)

You'll be able to feed these files into the library, including support for import statements so you can split schema into several files. You might notice one of the things in the schema file are generics, which has added quite a bit of complexity to the schema and buffer creation process.

Before, you really only had one buffer type per factory, so making a buffer looked like this:

let mut buffer = factory.new_buffer(None);

Now you'll need to do something like this:

let mut buffer = factory.new_buffer("my_type", None);

If the data type you're requesting has generics, you'll need to drop that in as well:

let mut buffer = factory.new_buffer("my_type<u32>", None);

As kind of a natural progression of this, you'll be able spin up custom types on the fly, including things like making a tuple type without first declaring it in the schema:

let mut buffer = factory.new_buffer("(u32, u32, my_type, my_generic_type<u32>)", None);

This adds a great deal of complexity to the new_buffer method. We've now got to calculate the size of all nested data structures with respect to the generic arguments.

As far as RPC is concerned, I think it's going to just be a data type for the buffers. Might still have an explicit API to keep things easier, but should look something like this:

// create method call
let mut buffer = factory.rpc_call("my_data_type.some_method", None);
// create method return
let mut buffer = factory.rpc_return("my_data_type.some_method", None);

Those are my current ideas so far, hope all of that makes sense!

janjaapbos commented 2 years ago

Looks very promising.

Another aspect that I have been thinking about is how to use the noproto values in the application code in a more Rusty way that using the get/set methods with the index. Would it make sense to create Rust traits that act as a lazy getter / setter for attributes for the underlying noproto objects? This would mean of course that you must have idea of the types used at compile time, but maintain some flexibitly due to optional nature of the attributes.

only-cliches commented 2 years ago

Yeah, I completely agree with you that the get and set methods aren't very Rusty!

I had always planned to add macros to this crate at some point, so you could do something similar/identical to serde. The big thing for me is stabilizing the API and the data format so all the work that goes into the macros doesn't get thrown away a few months later.

We'll even be able to do macros with the impl definitions at some point, including being able to generate schemas FROM your macro definitions so they can be used by third parties accessing your API.

I'd like a world where I can update the method name in my rust code on the RPC interface, the method name update gets pushed to my schema file automatically, then a typescript file is built from the schema that can be used to talk to the RPC methods. We'll get there one day!

janjaapbos commented 2 years ago

That for sure would be fabulous!