New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tlv: add new RecordT[T] utility type #8121
tlv: add new RecordT[T] utility type #8121
Conversation
39e03b0
to
d7adb79
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to suggest a different approach:
We have a new interface I will refer to as LPSerializable
and then we constrain the T in the Record def like so Record[T LPSerializable]
.
The interface for LPSerializable would be as you'd expect: a pair of functions T -> []byte
and []byte -> T, error
, and possibly a size function T -> uint16
.
Thoughts?
What's What would this look like? We have My goal here was just carve out just something enough to fill a gap we perceived when trying to make new structs that use the pure TLV encoding. This PR lets a user take a primitive type, or something else that already implements the |
Length-Prefixed. I am not in any way attached to the name.
My commentary was on the fact that the existing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
@Roasbeef, remember to re-request review from reviewers when ready |
8c86137
to
2b2e5e8
Compare
Ok, take 3 of this PR:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My main question is around why we cant just let any uint be the TLV type? ie, do we need the code gen?
added a templating solution suggestion to the code gen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excited about this. Looks like you kinda hacked Phantom Types into go by exploiting the implicit zero constructor 👍🏼
Go doesn't allow normal primitive types as type param parameter. In C++, you could do something like An example in C++ would be like: template<unsigned int SIZE = 3>
struct Vector {
unsigned char buffer[SIZE];
};
Vector<3> test; |
This is more than just a language limitation. It's a limitation of the type theory that underlies most languages. To do something like that you need limited support for dependent types and most things won't have that and even if they do you'll run into numerous edge cases where things don't behave as expected unless the language supports full-blown DT's. So, even if you could do it that way, I'd caution against it. |
Went to remove the limit for the first 100 TLV types, but ran into something where it'll only generate up to |
2b2e5e8
to
8b0c72d
Compare
Newest version up, PTAL. There's no true limit on the first 100 types now (see above comment), and I fixed an issue that made it harder to user as a caller (needed to fully populate all the attrs in a new struct, instead of being able to rely on the zero values). Code generation now is also just for the generated types, no need for those helper functions or the type constraint union. |
tlv/internal/gen/gen
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to be committing the binary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, removed
val := wireCsv(5) | ||
|
||
wireMsg := coolWireMsg{ | ||
CsvDelay: NewRecordT[TlvType1](val), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh tight, I wasn't sure if we could do partial inference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah pretty nice for cases like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Send it 🚀
8337405
to
5d5c0b8
Compare
Will land this, then push a new tag for |
In this commit, we add some new code generation to the codebase. As we'll see in a future commit, this'll allow us to create a new Record[T, V] type, where T is actually a concrete _struct_ that implements a special interface that deems it as a valid TLV type.
This shouldn't need to be run again, as this implementation restricts things to just values 0-99, due to a hard upper limit with the way Go unions work under the hood.
In this commit, we add a new type, `RecordT[T, V]` to reduce some of the common boiler plate for TLV types. This type lets you take either a primitive type, or an existing Record, and gain common methods used to create tlv streams. It also serves as extra type annotation as well, since wire structs can use this to wrap any existing type and gain the relevant record methods. This implementation ensures that the very definition of the field also binds the TLV type value. It does this by using the generated code to map a struct like TlvType1 to an actually Type like Type(1).
5d5c0b8
to
63e86b7
Compare
In this commit, we add a new type,
Record[T]
to reduce some of the common boiler plate for TLV types. This time lets you take either a primitive type, or an existing Record, and gain common methods used to create tlv streams.It also serves as extra type annotation as well, since wire structs can use this to wrap any existing type and gain the relevant record methods.