-
Notifications
You must be signed in to change notification settings - Fork 690
[byecode utils] make struct layout generation work with serdegen #652
Conversation
eab5485
to
bc91059
Compare
For Do we care about the case where there are collisions if you use something like Or maybe you catch all of these collisions in the same code path that does it for |
let declaring_module = self | ||
.module_resolver | ||
.get_module_by_id(module_id)? | ||
.expect("Failed to resolve module"); |
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 see the function returns a Result
. Should these panics and asserts be errors?
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.
The intention is that the assert failures happen when you get bad input (incomplete module environment, wrong # of type params, etc.) and the Result
failures are intermittent issues due to (e.g.) disk I/O in the module environment.
let generics: Vec<String> = type_arguments | ||
.iter() | ||
.zip(normalized_struct.type_parameters.iter()) | ||
.filter_map(|(type_arg, type_param)| { |
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.
minor nit, I like filter_map
, but I feel like this would be more readable with distinct filter
and map
calls, since neither the filter function nor the mapping function inherently return an Option
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 found the conditional logic harder to write/understand by using the filter/map, so left it as is.
let generics: Vec<String> = type_arguments.iter().map(print_format_type).collect(); | ||
format!("{}::{}<{}>", module_id, name, generics.join(",")) | ||
format!( | ||
"{}{}{}{}{}{}", |
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.
Maybe this whole pattern section would be easier to read with write!
?
e.g.
let mut struct_key = String::new();
if !self.config.omit_addresses {
write!(f, "{}{}", module_id.address(), self.config.separator.as_deref().unwrap_or("::"));
}
write!(f, "{}{}{}", module_id.name(), self.config.separator.as_deref().unwrap_or("::"), name);
if !generics.is_empty() {
...
}
This way you would get a lot more code sharing
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.
Good suggestion, that is much more concise
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 don't think string can be used with write
unfortunately. I think +=
might work though?
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.
It works with string
.
// check for conflicts (e.g., 0x1::M::T and 0x2::M::T that both get stripped to M::T because | ||
// omit_addresses is on) |
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.
Ah, I think this is what I was talking about in my top level comment. Should we report conflicts regardless?
@@ -5,16 +5,6 @@ Command `sandbox generate struct-layouts --module storage/0x00000000000000000000 | |||
STRUCT: | |||
- t: U64 | |||
- b: BOOL | |||
AccountAddress: |
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.
Could you explain the test cases changes? I don't think I understand the code enough to understand the change
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.
Good catch--this was a mistake (used an empty map instead of default_registry()
in the new constructor. Now fixed.
One of the promises of generating layout YAML's for Move structs is that we can leverage `serdegen` to autogenerate wrapper types for Move structs in all the languages `serdegen` handles. This PR moves us closer to that. - Add `separator` option that allows replacing the Move source syntax separators ("::", "<", ">", ",") in type names with a user-defined string. This is helpful because a name like `0x1::M::T<u64>` is very unlikely to be a valid identifier in any of the languages `serdegen` handles. Setting (e.g.) `separator = __` allows a fully qualified Move type name to be a valid identifier. - Add an `omit_addresses` option that omits the addresses from a fully qualified Move type name. This is useful in the (common) case where you are generating bindings for a package that does not have any name conflicts and don't want to bother with the addresses. The generator looks for name conflicts and panics if it finds one. -Add an `ignore_phantom_types` option that does not include phantom type parameters in struct names, since they do not influence layout. After these changes, the following PoC for serdegen works: ``` move sandbox generate struct-layouts --module storage/0x00000000000000000000000000000001/modules/M1.mv --struct G --omit-addresses --separator "__" > test.yaml serdegen --language python3 test.yaml > test.py python test.py ``` , where `test.py` is ``` from dataclasses import dataclass import typing import serde_types as st @DataClass(frozen=True) class M1__G: x: st.uint64 s: "M1__S__bool__" @DataClass(frozen=True) class M1__S__bool__: t: bool ```
bc91059
to
55d8369
Compare
Good call--added collision checks whenever separator is not |
One of the promises of generating layout YAML's for Move structs is that we can leverage
serdegen
to autogenerate wrapper types for Move structs in all the languagesserdegen
handles. This PR moves us closer to that.separator
option that allows replacing the Move source syntax separators ("::", "<", ">", ",") in type names with a user-defined string. This is helpful because a name like
0x1::M::T<u64>
is very unlikely to be a valid identifier in any of the languages
serdegen
handles. Setting (e.g.)separator = __
allows a fully qualified Move type name to be a valid identifier.omit_addresses
option that omits the addresses from a fully qualified Move type name. This is useful in the (common)case where you are generating bindings for a package that does not have any name conflicts and don't want to bother with the addresses. The generator looks for name conflicts and panics if it finds one.
ignore_phantom_types
option that does not include phantom type parameters in struct names, since they do not influence layout.After these changes, the following PoC for serdegen works:
move sandbox generate struct-layouts --module storage/0x00000000000000000000000000000001/modules/M1.mv --struct G --omit-addresses --separator "__" > test.yaml serdegen --language python3 test.yaml > test.py python test.py
, where
test.py
is