Bindgen as_Foo and into_Foo for variants

This commit is contained in:
Richard Feldman 2022-05-12 14:46:51 -04:00
parent 1de7d8abb6
commit 49cf2a8483
No known key found for this signature in database
GPG Key ID: 7E4127D1E4241798
2 changed files with 116 additions and 4 deletions

View File

@ -190,10 +190,20 @@ fn write_tag_union(
if let Some(payload_id) = opt_payload_id {
let payload_type = types.get(*payload_id);
let payload_name = if payload_type.has_pointer(types) {
"core::mem::ManuallyDrop::new(payload)"
let (init_payload, get_payload, deref_for_as) = if payload_type.has_pointer(types) {
(
"core::mem::ManuallyDrop::new(payload)",
format!(
"core::mem::ManuallyDrop::<{}>::into_inner(self.variant.{})",
type_name(*payload_id, types),
tag_name
),
// Since this is a ManuallyDrop, our `as_` method will need
// to dereference the variant (e.g. `&self.variant.Foo`)
"&",
)
} else {
"payload"
("payload", format!("self.variant.{}", tag_name), "")
};
let payload_type_name = type_name(*payload_id, types);
@ -218,7 +228,37 @@ fn write_tag_union(
tag_name,
variant_name,
tag_name,
payload_name
init_payload
)?;
writeln!(
buf,
// Don't use indoc because this must be indented once!
r#"
/// Unsafely assume the given {} has a .tag() of {} and convert it to {}'s payload.
/// (always examine .tag() first to make sure this is the correct variant!)
pub unsafe fn into_{}(self) -> {} {{
{}
}}"#,
name, tag_name, tag_name, tag_name, payload_type_name, get_payload
)?;
writeln!(
buf,
// Don't use indoc because this must be indented once!
r#"
/// Unsafely assume the given {} has a .tag() of {} and return its payload.
/// (always examine .tag() first to make sure this is the correct variant!)
pub unsafe fn as_{}(&self) -> {}{} {{
{}self.variant.{}
}}"#,
name,
tag_name,
tag_name,
deref_for_as,
payload_type_name,
deref_for_as,
tag_name
)?;
} else {
writeln!(
@ -239,6 +279,30 @@ fn write_tag_union(
}}"#,
tag_name, tag_name, discriminant_name, tag_name, variant_name, variant_name,
)?;
writeln!(
buf,
// Don't use indoc because this must be indented once!
r#"
/// Other `into_` methods return a payload, but since the {} tag
/// has no payload, this does nothing and is only here for completeness.
pub fn into_{}(self) -> () {{
()
}}"#,
tag_name, tag_name
)?;
writeln!(
buf,
// Don't use indoc because this must be indented once!
r#"
/// Other `as` methods return a payload, but since the {} tag
/// has no payload, this does nothing and is only here for completeness.
pub unsafe fn as_{}(&self) -> () {{
()
}}"#,
tag_name, tag_name
)?;
}
}

View File

@ -223,6 +223,18 @@ fn tag_union_aliased() {
}
}
/// Unsafely assume the given MyTagUnion has a .tag() of Bar and convert it to Bar's payload.
/// (always examine .tag() first to make sure this is the correct variant!)
pub unsafe fn into_Bar(self) -> u128 {
self.variant.Bar
}
/// Unsafely assume the given MyTagUnion has a .tag() of Bar and return its payload.
/// (always examine .tag() first to make sure this is the correct variant!)
pub unsafe fn as_Bar(&self) -> u128 {
self.variant.Bar
}
/// Construct a tag named Baz
pub fn Baz() -> Self {
Self {
@ -236,6 +248,18 @@ fn tag_union_aliased() {
}
}
/// Other `into_` methods return a payload, but since the Baz tag
/// has no payload, this does nothing and is only here for completeness.
pub fn into_Baz(self) -> () {
()
}
/// Other `as` methods return a payload, but since the Baz tag
/// has no payload, this does nothing and is only here for completeness.
pub unsafe fn as_Baz(&self) -> () {
()
}
/// Construct a tag named Blah, with the appropriate payload
pub fn Blah(payload: i32) -> Self {
Self {
@ -246,6 +270,18 @@ fn tag_union_aliased() {
}
}
/// Unsafely assume the given MyTagUnion has a .tag() of Blah and convert it to Blah's payload.
/// (always examine .tag() first to make sure this is the correct variant!)
pub unsafe fn into_Blah(self) -> i32 {
self.variant.Blah
}
/// Unsafely assume the given MyTagUnion has a .tag() of Blah and return its payload.
/// (always examine .tag() first to make sure this is the correct variant!)
pub unsafe fn as_Blah(&self) -> i32 {
self.variant.Blah
}
/// Construct a tag named Foo, with the appropriate payload
pub fn Foo(payload: roc_std::RocStr) -> Self {
Self {
@ -255,6 +291,18 @@ fn tag_union_aliased() {
},
}
}
/// Unsafely assume the given MyTagUnion has a .tag() of Foo and convert it to Foo's payload.
/// (always examine .tag() first to make sure this is the correct variant!)
pub unsafe fn into_Foo(self) -> roc_std::RocStr {
core::mem::ManuallyDrop::<roc_std::RocStr>::into_inner(self.variant.Foo)
}
/// Unsafely assume the given MyTagUnion has a .tag() of Foo and return its payload.
/// (always examine .tag() first to make sure this is the correct variant!)
pub unsafe fn as_Foo(&self) -> &roc_std::RocStr {
&self.variant.Foo
}
}
impl Drop for MyTagUnion {