Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions pdl-compiler/src/backends/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,10 @@ fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2:
})
.collect::<Vec<_>>();
ranges.sort_unstable();
ranges.first().unwrap().0 == 0
// An enum that declares no value or range tag cannot cover the backing
// integer range, and `first`/`last` would be `None` below.
!ranges.is_empty()
&& ranges.first().unwrap().0 == 0
&& ranges.last().unwrap().1 == max
&& ranges.windows(2).all(|window| {
if let [left, right] = window { left.1 == right.0 - 1 } else { false }
Expand Down Expand Up @@ -1055,24 +1058,31 @@ fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2:
}

// Generate the default enum value.
// The default value is the first tag of the enum.
// If the first tag identifies a range, then the first value
// of the range is used.
let default_value = match &tags[0] {
ast::Tag::Value(ast::TagValue { id, .. }) => {
// The default value is the first tag of the enum that is not the default
// (`Other`) tag. If the first tag identifies a range, then the first value
// of the range is used. If the enum declares no tag other than the default
// tag, the default tag is used.
let default_value = match tags.iter().find(|tag| !matches!(tag, ast::Tag::Other(_))) {
Some(ast::Tag::Value(ast::TagValue { id, .. })) => {
let id = format_tag_ident(id);
quote! { #name::#id }
}
ast::Tag::Range(ast::TagRange { tags, .. }) if !tags.is_empty() => {
Some(ast::Tag::Range(ast::TagRange { tags, .. })) if !tags.is_empty() => {
let id = format_tag_ident(&tags[0].id);
quote! { #name::#id }
}
ast::Tag::Range(ast::TagRange { id, range, .. }) => {
Some(ast::Tag::Range(ast::TagRange { id, range, .. })) => {
let id = format_tag_ident(id);
let value = format_value(*range.start());
quote! { #name::#id(Private(#value)) }
}
ast::Tag::Other(_) => todo!(),
// `find` skips `Tag::Other`, so the remaining case is an enum whose
// only declared tag is the default tag.
_ => {
let id = format_tag_ident(&default_tag.as_ref().expect("enum declares at least one tag").id);
let value = format_value(0);
quote! { #name::#id(Private(#value)) }
}
};

// Generate the cases for parsing the enum value from an integer.
Expand Down Expand Up @@ -1483,6 +1493,15 @@ mod tests {
B = 1,
C = 2..255,
}

enum OpenWithDefaultTagFirst : 8 {
UNKNOWN = ..,
A = 0,
}

enum OpenWithOnlyDefaultTag : 8 {
UNKNOWN = ..,
}
"#
);

Expand Down
125 changes: 125 additions & 0 deletions pdl-compiler/tests/generated/rust/enum_declaration_big_endian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,3 +554,128 @@ impl From<CompleteWithRange> for u64 {
u8::from(value) as Self
}
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
pub enum OpenWithDefaultTagFirst {
A,
Unknown(Private<u8>),
}
impl Default for OpenWithDefaultTagFirst {
fn default() -> OpenWithDefaultTagFirst {
OpenWithDefaultTagFirst::A
}
}
impl TryFrom<u8> for OpenWithDefaultTagFirst {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x0 => Ok(OpenWithDefaultTagFirst::A),
0..=0xff => Ok(OpenWithDefaultTagFirst::Unknown(Private(value))),
}
}
}
impl From<&OpenWithDefaultTagFirst> for u8 {
fn from(value: &OpenWithDefaultTagFirst) -> Self {
match value {
OpenWithDefaultTagFirst::A => 0x0,
OpenWithDefaultTagFirst::Unknown(Private(value)) => *value,
}
}
}
impl From<OpenWithDefaultTagFirst> for u8 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
(&value).into()
}
}
impl From<OpenWithDefaultTagFirst> for i16 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for i32 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for i64 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for u16 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for u32 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for u64 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
pub enum OpenWithOnlyDefaultTag {
Unknown(Private<u8>),
}
impl Default for OpenWithOnlyDefaultTag {
fn default() -> OpenWithOnlyDefaultTag {
OpenWithOnlyDefaultTag::Unknown(Private(0x0))
}
}
impl TryFrom<u8> for OpenWithOnlyDefaultTag {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0..=0xff => Ok(OpenWithOnlyDefaultTag::Unknown(Private(value))),
}
}
}
impl From<&OpenWithOnlyDefaultTag> for u8 {
fn from(value: &OpenWithOnlyDefaultTag) -> Self {
match value {
OpenWithOnlyDefaultTag::Unknown(Private(value)) => *value,
}
}
}
impl From<OpenWithOnlyDefaultTag> for u8 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
(&value).into()
}
}
impl From<OpenWithOnlyDefaultTag> for i16 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for i32 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for i64 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for u16 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for u32 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for u64 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
125 changes: 125 additions & 0 deletions pdl-compiler/tests/generated/rust/enum_declaration_little_endian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,3 +554,128 @@ impl From<CompleteWithRange> for u64 {
u8::from(value) as Self
}
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
pub enum OpenWithDefaultTagFirst {
A,
Unknown(Private<u8>),
}
impl Default for OpenWithDefaultTagFirst {
fn default() -> OpenWithDefaultTagFirst {
OpenWithDefaultTagFirst::A
}
}
impl TryFrom<u8> for OpenWithDefaultTagFirst {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x0 => Ok(OpenWithDefaultTagFirst::A),
0..=0xff => Ok(OpenWithDefaultTagFirst::Unknown(Private(value))),
}
}
}
impl From<&OpenWithDefaultTagFirst> for u8 {
fn from(value: &OpenWithDefaultTagFirst) -> Self {
match value {
OpenWithDefaultTagFirst::A => 0x0,
OpenWithDefaultTagFirst::Unknown(Private(value)) => *value,
}
}
}
impl From<OpenWithDefaultTagFirst> for u8 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
(&value).into()
}
}
impl From<OpenWithDefaultTagFirst> for i16 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for i32 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for i64 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for u16 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for u32 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithDefaultTagFirst> for u64 {
fn from(value: OpenWithDefaultTagFirst) -> Self {
u8::from(value) as Self
}
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
pub enum OpenWithOnlyDefaultTag {
Unknown(Private<u8>),
}
impl Default for OpenWithOnlyDefaultTag {
fn default() -> OpenWithOnlyDefaultTag {
OpenWithOnlyDefaultTag::Unknown(Private(0x0))
}
}
impl TryFrom<u8> for OpenWithOnlyDefaultTag {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0..=0xff => Ok(OpenWithOnlyDefaultTag::Unknown(Private(value))),
}
}
}
impl From<&OpenWithOnlyDefaultTag> for u8 {
fn from(value: &OpenWithOnlyDefaultTag) -> Self {
match value {
OpenWithOnlyDefaultTag::Unknown(Private(value)) => *value,
}
}
}
impl From<OpenWithOnlyDefaultTag> for u8 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
(&value).into()
}
}
impl From<OpenWithOnlyDefaultTag> for i16 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for i32 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for i64 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for u16 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for u32 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
impl From<OpenWithOnlyDefaultTag> for u64 {
fn from(value: OpenWithOnlyDefaultTag) -> Self {
u8::from(value) as Self
}
}
Loading