From 035e4aa50a1a040e11db58d5c376bfea25a7a213 Mon Sep 17 00:00:00 2001 From: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:41:11 -0400 Subject: [PATCH 01/17] Remove nightly from rustdoc v28 test matrix, since that's now v29. (#332) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af3bf584..6a5b647d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - toolchain: ["1.77", "beta", "nightly"] + toolchain: ["1.77", "beta"] steps: - name: Checkout uses: actions/checkout@v4 From a0a13fba60412ab7cf5c7149bdd420cf00af5a3b Mon Sep 17 00:00:00 2001 From: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> Date: Sun, 16 Jun 2024 14:47:05 -0400 Subject: [PATCH 02/17] Rust 1.78 is no longer beta. (#334) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a5b647d..27bd41d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - toolchain: ["1.77", "beta"] + toolchain: ["1.77", "1.78"] steps: - name: Checkout uses: actions/checkout@v4 From 4bd03a12b468fd49991df54fca0425b2a059cd8e Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sun, 21 Jul 2024 18:00:58 -0400 Subject: [PATCH 03/17] Add enum discriminants --- src/adapter/edges.rs | 12 +++++ src/adapter/mod.rs | 3 ++ src/adapter/origin.rs | 10 ++++ src/adapter/properties.rs | 23 +++++++++ src/adapter/tests.rs | 60 +++++++++++++++++++++++ src/adapter/vertex.rs | 19 ++++++- src/rustdoc_schema.graphql | 12 +++++ test_crates/enum_discriminants/Cargo.toml | 9 ++++ test_crates/enum_discriminants/src/lib.rs | 5 ++ 9 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 test_crates/enum_discriminants/Cargo.toml create mode 100644 test_crates/enum_discriminants/src/lib.rs diff --git a/src/adapter/edges.rs b/src/adapter/edges.rs index 2bd328cc..90e1e9a7 100644 --- a/src/adapter/edges.rs +++ b/src/adapter/edges.rs @@ -293,6 +293,18 @@ pub(super) fn resolve_variant_edge<'a, V: AsVertex> + 'a>( })), } }), + "discriminant" => resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let item = vertex.as_variant().expect("vertex was not a Variant"); + + if let Some(discriminant) = &item.discriminant { + Box::new(std::iter::once( + origin.make_discriminant_vertex(discriminant.clone()), + )) + } else { + Box::new(std::iter::empty()) + } + }), _ => unreachable!("resolve_variant_edge {edge_name}"), } } diff --git a/src/adapter/mod.rs b/src/adapter/mod.rs index 29569e0c..e4d16670 100644 --- a/src/adapter/mod.rs +++ b/src/adapter/mod.rs @@ -150,6 +150,9 @@ impl<'a> Adapter<'a> for RustdocAdapter<'a> { properties::resolve_associated_constant_property(contexts, property_name) } "Constant" => properties::resolve_constant_property(contexts, property_name), + "Discriminant" => { + properties::resolve_discriminant_property(contexts, property_name) + } _ => unreachable!("resolve_property {type_name} {property_name}"), } } diff --git a/src/adapter/origin.rs b/src/adapter/origin.rs index 5d92bdce..9225ce4d 100644 --- a/src/adapter/origin.rs +++ b/src/adapter/origin.rs @@ -96,4 +96,14 @@ impl Origin { kind: abi.into(), } } + + pub(super) fn make_discriminant_vertex<'a>( + &self, + discriminant: rustdoc_types::Discriminant, + ) -> Vertex<'a> { + Vertex { + origin: *self, + kind: discriminant.into(), + } + } } diff --git a/src/adapter/properties.rs b/src/adapter/properties.rs index 7873c5cc..d5b38e58 100644 --- a/src/adapter/properties.rs +++ b/src/adapter/properties.rs @@ -560,3 +560,26 @@ pub(crate) fn resolve_constant_property<'a, V: AsVertex> + 'a>( _ => unreachable!("Constant property {property_name}"), } } + +pub(crate) fn resolve_discriminant_property<'a, V: AsVertex> + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &str, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match property_name { + "expr" => resolve_property_with(contexts, |vertex| { + vertex + .as_discriminant() + .expect("vertex was not a Discriminant") + .expr + .into() + }), + "value" => resolve_property_with(contexts, |vertex| { + vertex + .as_discriminant() + .expect("vertex was not a Discriminant") + .value + .into() + }), + _ => unreachable!("AssociatedConstant property {property_name}"), + } +} diff --git a/src/adapter/tests.rs b/src/adapter/tests.rs index 8dff6e93..c3c94c1f 100644 --- a/src/adapter/tests.rs +++ b/src/adapter/tests.rs @@ -1657,3 +1657,63 @@ fn unions() { similar_asserts::assert_eq!(expected_results, results); } + +#[test] +fn enum_discriminants() { + let path = "./localdata/test_data/enum_discriminants/rustdoc.json"; + let content = std::fs::read_to_string(path) + .with_context(|| format!("Could not load {path} file, did you forget to run ./scripts/regenerate_test_rustdocs.sh ?")) + .expect("failed to load rustdoc"); + + let crate_ = serde_json::from_str(&content).expect("failed to parse rustdoc"); + let indexed_crate = IndexedCrate::new(&crate_); + let adapter = RustdocAdapter::new(&indexed_crate, None); + + let query = r#" +{ + Crate { + item { + ... on Enum { + variant { + discriminant { + expr @output + value @output + } + } + } + } + } +} +"#; + let variables: BTreeMap<&str, &str> = btreemap! {}; + + let schema = + Schema::parse(include_str!("../rustdoc_schema.graphql")).expect("schema failed to parse"); + + #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, serde::Deserialize)] + struct Output { + expr: String, + value: String, + } + + let mut results: Vec = + trustfall::execute_query(&schema, adapter.into(), query, variables.clone()) + .expect("failed to run query") + .map(|row| row.try_into_struct().expect("shape mismatch")) + .collect(); + results.sort_unstable(); + + similar_asserts::assert_eq!( + vec![ + Output { + expr: "1".into(), + value: "1".into(), + }, + Output { + expr: "{ _ }".into(), + value: "2".into(), + }, + ], + results + ); +} diff --git a/src/adapter/vertex.rs b/src/adapter/vertex.rs index 94fc48be..38304375 100644 --- a/src/adapter/vertex.rs +++ b/src/adapter/vertex.rs @@ -1,8 +1,8 @@ use std::rc::Rc; use rustdoc_types::{ - Abi, Constant, Crate, Enum, Function, Impl, Item, Module, Path, Span, Static, Struct, Trait, - Type, Union, Variant, VariantKind, + Abi, Constant, Crate, Discriminant, Enum, Function, Impl, Item, Module, Path, Span, Static, + Struct, Trait, Type, Union, Variant, VariantKind, }; use trustfall::provider::Typename; @@ -36,6 +36,7 @@ pub enum VertexKind<'a> { ImplementedTrait(&'a Path, &'a Item), FunctionParameter(&'a str), FunctionAbi(&'a Abi), + Discriminant(Discriminant), } impl<'a> Typename for Vertex<'a> { @@ -77,6 +78,7 @@ impl<'a> Typename for Vertex<'a> { }, VertexKind::FunctionParameter(..) => "FunctionParameter", VertexKind::FunctionAbi(..) => "FunctionAbi", + VertexKind::Discriminant(..) => "Discriminant", } } } @@ -254,6 +256,13 @@ impl<'a> Vertex<'a> { _ => None, } } + + pub(super) fn as_discriminant(&self) -> Option { + match &self.kind { + VertexKind::Discriminant(discriminant) => Some(discriminant.clone()), + _ => None, + } + } } impl<'a> From<&'a Item> for VertexKind<'a> { @@ -279,3 +288,9 @@ impl<'a> From<&'a Abi> for VertexKind<'a> { Self::FunctionAbi(a) } } + +impl<'a> From for VertexKind<'a> { + fn from(d: Discriminant) -> Self { + Self::Discriminant(d) + } +} diff --git a/src/rustdoc_schema.graphql b/src/rustdoc_schema.graphql index 9a6b07a6..2f766d56 100644 --- a/src/rustdoc_schema.graphql +++ b/src/rustdoc_schema.graphql @@ -429,6 +429,15 @@ interface Variant implements Item { # own edges field: [StructField!] + discriminant: Discriminant +} + +""" +https://docs.rs/rustdoc-types/latest/rustdoc_types/struct.Discriminant.html +""" +type Discriminant { + expr: String! + value: String! } """ @@ -483,6 +492,7 @@ type PlainVariant implements Item & Variant { # edges from Variant field: [StructField!] + discriminant: Discriminant } """ @@ -537,6 +547,7 @@ type TupleVariant implements Item & Variant { # edges from Variant field: [StructField!] + discriminant: Discriminant } """ @@ -591,6 +602,7 @@ type StructVariant implements Item & Variant { # edges from Variant field: [StructField!] + discriminant: Discriminant } """ diff --git a/test_crates/enum_discriminants/Cargo.toml b/test_crates/enum_discriminants/Cargo.toml new file mode 100644 index 00000000..e9b8c5fa --- /dev/null +++ b/test_crates/enum_discriminants/Cargo.toml @@ -0,0 +1,9 @@ +[package] +publish = false +name = "enum_discriminants" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/test_crates/enum_discriminants/src/lib.rs b/test_crates/enum_discriminants/src/lib.rs new file mode 100644 index 00000000..5b57eebb --- /dev/null +++ b/test_crates/enum_discriminants/src/lib.rs @@ -0,0 +1,5 @@ +#[repr(C)] +pub enum A { + One = 1, + Two = 1 + 1, +} From a9bbecb05a2ae60d2f9364efb33b6d7a75f8af64 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sun, 21 Jul 2024 21:18:11 -0400 Subject: [PATCH 04/17] discriminant clone to lifetime annotation --- src/adapter/edges.rs | 2 +- src/adapter/origin.rs | 2 +- src/adapter/properties.rs | 16 ++-------------- src/adapter/vertex.rs | 10 +++++----- 4 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/adapter/edges.rs b/src/adapter/edges.rs index 90e1e9a7..a33f15a0 100644 --- a/src/adapter/edges.rs +++ b/src/adapter/edges.rs @@ -299,7 +299,7 @@ pub(super) fn resolve_variant_edge<'a, V: AsVertex> + 'a>( if let Some(discriminant) = &item.discriminant { Box::new(std::iter::once( - origin.make_discriminant_vertex(discriminant.clone()), + origin.make_discriminant_vertex(discriminant), )) } else { Box::new(std::iter::empty()) diff --git a/src/adapter/origin.rs b/src/adapter/origin.rs index 9225ce4d..7a57e245 100644 --- a/src/adapter/origin.rs +++ b/src/adapter/origin.rs @@ -99,7 +99,7 @@ impl Origin { pub(super) fn make_discriminant_vertex<'a>( &self, - discriminant: rustdoc_types::Discriminant, + discriminant: &'a rustdoc_types::Discriminant, ) -> Vertex<'a> { Vertex { origin: *self, diff --git a/src/adapter/properties.rs b/src/adapter/properties.rs index d5b38e58..088fd7fe 100644 --- a/src/adapter/properties.rs +++ b/src/adapter/properties.rs @@ -566,20 +566,8 @@ pub(crate) fn resolve_discriminant_property<'a, V: AsVertex> + 'a>( property_name: &str, ) -> ContextOutcomeIterator<'a, V, FieldValue> { match property_name { - "expr" => resolve_property_with(contexts, |vertex| { - vertex - .as_discriminant() - .expect("vertex was not a Discriminant") - .expr - .into() - }), - "value" => resolve_property_with(contexts, |vertex| { - vertex - .as_discriminant() - .expect("vertex was not a Discriminant") - .value - .into() - }), + "expr" => resolve_property_with(contexts, field_property!(as_discriminant, expr)), + "value" => resolve_property_with(contexts, field_property!(as_discriminant, value)), _ => unreachable!("AssociatedConstant property {property_name}"), } } diff --git a/src/adapter/vertex.rs b/src/adapter/vertex.rs index 38304375..6a37bffb 100644 --- a/src/adapter/vertex.rs +++ b/src/adapter/vertex.rs @@ -36,7 +36,7 @@ pub enum VertexKind<'a> { ImplementedTrait(&'a Path, &'a Item), FunctionParameter(&'a str), FunctionAbi(&'a Abi), - Discriminant(Discriminant), + Discriminant(&'a Discriminant), } impl<'a> Typename for Vertex<'a> { @@ -257,9 +257,9 @@ impl<'a> Vertex<'a> { } } - pub(super) fn as_discriminant(&self) -> Option { + pub(super) fn as_discriminant(&self) -> Option<&'a rustdoc_types::Discriminant> { match &self.kind { - VertexKind::Discriminant(discriminant) => Some(discriminant.clone()), + VertexKind::Discriminant(discriminant) => Some(discriminant), _ => None, } } @@ -289,8 +289,8 @@ impl<'a> From<&'a Abi> for VertexKind<'a> { } } -impl<'a> From for VertexKind<'a> { - fn from(d: Discriminant) -> Self { +impl<'a> From<&'a Discriminant> for VertexKind<'a> { + fn from(d: &'a Discriminant) -> Self { Self::Discriminant(d) } } From 7a8ea8aa76c32653b3442f0a9bfaf5a3f1ccc91e Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sun, 21 Jul 2024 21:50:30 -0400 Subject: [PATCH 05/17] complicate test examples --- src/adapter/tests.rs | 24 +++++++++++++++++++++++ test_crates/enum_discriminants/src/lib.rs | 24 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/adapter/tests.rs b/src/adapter/tests.rs index c3c94c1f..770bc809 100644 --- a/src/adapter/tests.rs +++ b/src/adapter/tests.rs @@ -1674,6 +1674,7 @@ fn enum_discriminants() { Crate { item { ... on Enum { + name @output variant { discriminant { expr @output @@ -1692,6 +1693,7 @@ fn enum_discriminants() { #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, serde::Deserialize)] struct Output { + name: String, expr: String, value: String, } @@ -1706,13 +1708,35 @@ fn enum_discriminants() { similar_asserts::assert_eq!( vec![ Output { + name: "A".into(), expr: "1".into(), value: "1".into(), }, Output { + name: "A".into(), + expr: "99".into(), + value: "99".into(), + }, + Output { + name: "A".into(), expr: "{ _ }".into(), value: "2".into(), }, + Output { + name: "Fieldful".into(), + expr: "9".into(), + value: "9".into(), + }, + Output { + name: "FieldlessWithDiscrimants".into(), + expr: "10".into(), + value: "10".into(), + }, + Output { + name: "FieldlessWithDiscrimants".into(), + expr: "20".into(), + value: "20".into(), + }, ], results ); diff --git a/test_crates/enum_discriminants/src/lib.rs b/test_crates/enum_discriminants/src/lib.rs index 5b57eebb..eb09d0cd 100644 --- a/test_crates/enum_discriminants/src/lib.rs +++ b/test_crates/enum_discriminants/src/lib.rs @@ -1,5 +1,29 @@ +/// Some examples from + #[repr(C)] pub enum A { + Zero, One = 1, Two = 1 + 1, + Three, + Four = 99, + Five } + +#[repr(u8)] +pub enum FieldlessWithDiscrimants { + First = 10, + Tuple(), + Second = 20, + Struct{}, + Unit, +} + +#[repr(i64)] +pub enum Fieldful { + Unit, + Tuple(bool), + Struct{a: bool}, + Unit2 = 9 +} + From 693ffceb9490e5219375bc3e27da0bb4f24566b6 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sun, 21 Jul 2024 22:07:07 -0400 Subject: [PATCH 06/17] improved discriminant docs --- src/rustdoc_schema.graphql | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/rustdoc_schema.graphql b/src/rustdoc_schema.graphql index 2f766d56..ab91f676 100644 --- a/src/rustdoc_schema.graphql +++ b/src/rustdoc_schema.graphql @@ -429,14 +429,28 @@ interface Variant implements Item { # own edges field: [StructField!] + + """ + The discriminant, if explicitly specified. + """ discriminant: Discriminant } """ -https://docs.rs/rustdoc-types/latest/rustdoc_types/struct.Discriminant.html +https://docs.rs/rustdoc-types/0.28.0/rustdoc_types/struct.Discriminant.html +https://doc.rust-lang.org/reference/items/enumerations.html """ type Discriminant { + """ + The expression that produced the discriminant. Preserves the original formatting seen in source code (e.g. suffixes, hexadecimal, and underscores). + + In some cases, when the value is to complex, this may be "`{ _ }`". + """ expr: String! + + """ + The numerical value of the discriminant. Stored as a string. Ranges from `i128::MIN` to `u128::MAX`. + """ value: String! } From 7e3046326a4ff21d275f411b5a8201479b4b6200 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Mon, 22 Jul 2024 10:33:25 -0400 Subject: [PATCH 07/17] hedge bets against placeholder representation Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> --- src/rustdoc_schema.graphql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustdoc_schema.graphql b/src/rustdoc_schema.graphql index ab91f676..7fea71c0 100644 --- a/src/rustdoc_schema.graphql +++ b/src/rustdoc_schema.graphql @@ -444,7 +444,7 @@ type Discriminant { """ The expression that produced the discriminant. Preserves the original formatting seen in source code (e.g. suffixes, hexadecimal, and underscores). - In some cases, when the value is to complex, this may be "`{ _ }`". + In some cases, when the value is too complex, this may be a placeholder value such as `"{ _ }"`. """ expr: String! From 8f50c7063c6a1cf46942db6de652e3acf496bca5 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Fri, 26 Jul 2024 16:25:07 -0400 Subject: [PATCH 08/17] finally got implicit discriminants working --- src/adapter/edges.rs | 52 +++- src/adapter/enum_variant.rs | 304 ++++++++++++++++++++++ src/adapter/mod.rs | 1 + src/adapter/origin.rs | 22 +- src/adapter/properties.rs | 11 +- src/adapter/tests.rs | 62 ++++- src/adapter/vertex.rs | 50 ++-- src/rustdoc_schema.graphql | 7 - test_crates/enum_discriminants/src/lib.rs | 9 + 9 files changed, 459 insertions(+), 59 deletions(-) create mode 100644 src/adapter/enum_variant.rs diff --git a/src/adapter/edges.rs b/src/adapter/edges.rs index a33f15a0..b87403e3 100644 --- a/src/adapter/edges.rs +++ b/src/adapter/edges.rs @@ -1,4 +1,5 @@ -use rustdoc_types::{GenericBound::TraitBound, Id, ItemEnum, VariantKind}; +use rustdoc_types::{GenericBound::TraitBound, Id, ItemEnum, Variant, VariantKind}; +use std::sync::Arc; use trustfall::provider::{ resolve_neighbors_with, AsVertex, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, VertexIterator, @@ -6,7 +7,9 @@ use trustfall::provider::{ use crate::{adapter::supported_item_kind, attributes::Attribute, IndexedCrate}; -use super::{optimizations, origin::Origin, vertex::Vertex, RustdocAdapter}; +use super::{ + enum_variant::LazyDiscriminants, optimizations, origin::Origin, vertex::Vertex, RustdocAdapter, +}; pub(super) fn resolve_crate_diff_edge<'a, V: AsVertex> + 'a>( contexts: ContextIterator<'a, V>, @@ -295,15 +298,10 @@ pub(super) fn resolve_variant_edge<'a, V: AsVertex> + 'a>( }), "discriminant" => resolve_neighbors_with(contexts, move |vertex| { let origin = vertex.origin; - let item = vertex.as_variant().expect("vertex was not a Variant"); - - if let Some(discriminant) = &item.discriminant { - Box::new(std::iter::once( - origin.make_discriminant_vertex(discriminant), - )) - } else { - Box::new(std::iter::empty()) - } + let enum_var = vertex.as_enum_variant().expect("vertex was not a Variant"); + Box::new(std::iter::once( + origin.make_discriminant_vertex(enum_var.discriminant().clone()), + )) }), _ => unreachable!("resolve_variant_edge {edge_name}"), } @@ -329,9 +327,35 @@ pub(super) fn resolve_enum_edge<'a, V: AsVertex> + 'a>( .index } }; - Box::new(enum_item.variants.iter().map(move |field_id| { - origin.make_item_vertex(item_index.get(field_id).expect("missing item")) - })) + + let discriminants = { + let variants: Vec<&Variant> = enum_item + .variants + .iter() + .map(move |field_id| { + let inner = &item_index.get(field_id).expect("missing item").inner; + match inner { + ItemEnum::Variant(v) => v, + _ => unreachable!("Item {inner:?} not a Variant"), + } + }) + .collect(); + Arc::new(LazyDiscriminants::new(variants)) + }; + + Box::new( + enum_item + .variants + .iter() + .enumerate() + .map(move |(index, field_id)| { + origin.make_variant_vertex( + item_index.get(field_id).expect("missing item"), + discriminants.clone(), + index, + ) + }), + ) }), _ => unreachable!("resolve_enum_edge {edge_name}"), } diff --git a/src/adapter/enum_variant.rs b/src/adapter/enum_variant.rs new file mode 100644 index 00000000..7d33b760 --- /dev/null +++ b/src/adapter/enum_variant.rs @@ -0,0 +1,304 @@ +use rustdoc_types::{Item, ItemEnum, Variant}; +use std::fmt; +use std::num::ParseIntError; +use std::sync::Arc; +use std::{str::FromStr, sync::OnceLock}; + +#[non_exhaustive] +#[derive(Debug, Clone)] +pub(super) struct EnumVariant<'a> { + item: &'a Item, + discriminants: Arc>, + index: usize, +} + +#[non_exhaustive] +#[derive(Debug, Clone)] +pub(super) struct LazyDiscriminants<'a> { + variants: Vec<&'a Variant>, + discriminants: OnceLock>, +} + +impl<'a> LazyDiscriminants<'a> { + pub(super) fn new(variants: Vec<&'a Variant>) -> Self { + Self { + variants, + discriminants: OnceLock::new(), + } + } + + pub(super) fn get_discriminants(&self) -> &Vec { + self.discriminants + .get_or_init(|| assign_discriminants(&self.variants)) + } +} + +impl<'a> EnumVariant<'a> { + pub(super) fn new( + item: &'a Item, + discriminants: Arc>, + index: usize, + ) -> Self { + Self { + item, + discriminants, + index, + } + } + + pub(super) fn variant(&self) -> Option<&'a Variant> { + match &self.item.inner { + ItemEnum::Variant(v) => Some(v), + _ => None, + } + } + + pub(super) fn discriminant(&'a self) -> &'a String { + self.discriminants + .get_discriminants() + .get(self.index) + .unwrap() + } +} + +enum DiscriminantValue { + I64(i64), + U64(u64), + I128(i128), + U128(u128), +} + +impl DiscriminantValue { + pub fn max(&self) -> bool { + matches!(self, DiscriminantValue::U128(u128::MAX)) + } + + pub fn increment(&self) -> DiscriminantValue { + match self { + DiscriminantValue::I64(i) => { + match i.checked_add_unsigned(1) { + // No overflow + Some(i) => i.into(), + // Overflow, number will fit in a u64 + None => DiscriminantValue::from(u64::try_from(*i).unwrap()).increment(), + } + } + DiscriminantValue::U64(i) => { + match i.checked_add(1) { + // No overflow + Some(i) => i.into(), + // Overflow, number will fit in a i128 + None => DiscriminantValue::from(i128::from(*i)).increment(), + } + } + DiscriminantValue::I128(i) => { + match i.checked_add_unsigned(1) { + // No overflow + Some(i) => i.into(), + // Overflow, number will fit in a u128 + None => DiscriminantValue::from(u128::try_from(*i).unwrap()).increment(), + } + } + DiscriminantValue::U128(i) => (i + 1).into(), + } + } +} + +impl fmt::Display for DiscriminantValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DiscriminantValue::I64(i) => write!(f, "{}", i), + DiscriminantValue::U64(i) => write!(f, "{}", i), + DiscriminantValue::I128(i) => write!(f, "{}", i), + DiscriminantValue::U128(i) => write!(f, "{}", i), + } + } +} + +impl From for DiscriminantValue { + fn from(value: i64) -> Self { + DiscriminantValue::I64(value) + } +} + +impl From for DiscriminantValue { + fn from(value: i128) -> Self { + DiscriminantValue::I128(value) + } +} + +impl From for DiscriminantValue { + fn from(value: u64) -> Self { + DiscriminantValue::U64(value) + } +} + +impl From for DiscriminantValue { + fn from(value: u128) -> Self { + DiscriminantValue::U128(value) + } +} + +impl FromStr for DiscriminantValue { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result { + if let Ok(i) = i64::from_str(s) { + return Ok(i.into()); + } + if let Ok(i) = u64::from_str(s) { + return Ok(i.into()); + } + if let Ok(i) = i128::from_str(s) { + return Ok(i.into()); + } + match u128::from_str(s) { + Ok(i) => Ok(i.into()), + Err(e) => Err(e), + } + } +} + +/// +pub(super) fn assign_discriminants(variants: &Vec<&Variant>) -> Vec { + let mut last: DiscriminantValue = DiscriminantValue::I64(0); + let mut discriminants: Vec = Vec::with_capacity(variants.len()); + for v in variants { + discriminants.push(match &v.discriminant { + Some(d) => { + last = DiscriminantValue::from_str(&d.value).unwrap(); + d.value.clone() + } + None => last.to_string(), + }); + if !last.max() { + last = last.increment(); + } + } + discriminants +} + +#[cfg(test)] +mod tests { + use rustdoc_types::{Discriminant, VariantKind}; + + use super::*; + + #[test] + fn i64() { + let explicit_1 = Variant { + discriminant: Some(Discriminant { + value: "5".into(), + expr: "".into(), + }), + kind: VariantKind::Plain, + }; + let explicit_2 = Variant { + discriminant: Some(Discriminant { + value: "7".into(), + expr: "".into(), + }), + kind: VariantKind::Plain, + }; + let explicit_3 = Variant { + discriminant: Some(Discriminant { + value: "-59999".into(), + expr: "".into(), + }), + kind: VariantKind::Plain, + }; + let variants = vec![ + &Variant { + discriminant: None, + kind: VariantKind::Plain, + }, + &Variant { + discriminant: None, + kind: VariantKind::Plain, + }, + &explicit_1, + &explicit_2, + &Variant { + discriminant: None, + kind: VariantKind::Plain, + }, + &explicit_3, + &Variant { + discriminant: None, + kind: VariantKind::Plain, + }, + ]; + let actual = assign_discriminants(&variants); + let expected: Vec = vec![ + "0".into(), + "1".into(), + "5".into(), + "7".into(), + "8".into(), + "-59999".into(), + "-59998".into(), + ]; + assert_eq!(actual, expected); + } + + #[test] + fn max() { + let explicit_1 = Variant { + discriminant: Some(Discriminant { + value: i64::MAX.to_string(), + expr: "".into(), + }), + kind: VariantKind::Plain, + }; + let explicit_2 = Variant { + discriminant: Some(Discriminant { + value: u64::MAX.to_string(), + expr: "".into(), + }), + kind: VariantKind::Plain, + }; + let explicit_3 = Variant { + discriminant: Some(Discriminant { + value: i128::MAX.to_string(), + expr: "".into(), + }), + kind: VariantKind::Plain, + }; + let explicit_4 = Variant { + discriminant: Some(Discriminant { + value: u128::MAX.to_string(), + expr: "".into(), + }), + kind: VariantKind::Plain, + }; + let variants = vec![ + &explicit_1, + &Variant { + discriminant: None, + kind: VariantKind::Plain, + }, + &explicit_2, + &Variant { + discriminant: None, + kind: VariantKind::Plain, + }, + &explicit_3, + &Variant { + discriminant: None, + kind: VariantKind::Plain, + }, + &explicit_4, + ]; + let actual = assign_discriminants(&variants); + let expected: Vec = vec![ + "9223372036854775807".into(), + "9223372036854775808".into(), + "18446744073709551615".into(), + "18446744073709551616".into(), + "170141183460469231731687303715884105727".into(), + "170141183460469231731687303715884105728".into(), + "340282366920938463463374607431768211455".into(), + ]; + assert_eq!(actual, expected); + } +} diff --git a/src/adapter/mod.rs b/src/adapter/mod.rs index e4d16670..0a4e1542 100644 --- a/src/adapter/mod.rs +++ b/src/adapter/mod.rs @@ -17,6 +17,7 @@ use self::{ }; mod edges; +mod enum_variant; mod optimizations; mod origin; mod properties; diff --git a/src/adapter/origin.rs b/src/adapter/origin.rs index 7a57e245..3dea1459 100644 --- a/src/adapter/origin.rs +++ b/src/adapter/origin.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::{rc::Rc, sync::Arc}; use rustdoc_types::{Abi, Item, Span}; @@ -7,7 +7,10 @@ use crate::{ indexed_crate::ImportablePath, }; -use super::vertex::{Vertex, VertexKind}; +use super::{ + enum_variant::{EnumVariant, LazyDiscriminants}, + vertex::{Vertex, VertexKind}, +}; #[non_exhaustive] #[derive(Debug, Clone, Copy)] @@ -97,13 +100,22 @@ impl Origin { } } - pub(super) fn make_discriminant_vertex<'a>( + pub(super) fn make_discriminant_vertex<'a>(&self, value: String) -> Vertex<'a> { + Vertex { + origin: *self, + kind: VertexKind::Discriminant(value), + } + } + + pub(super) fn make_variant_vertex<'a>( &self, - discriminant: &'a rustdoc_types::Discriminant, + item: &'a Item, + discriminants: Arc>, + index: usize, ) -> Vertex<'a> { Vertex { origin: *self, - kind: discriminant.into(), + kind: VertexKind::Variant(EnumVariant::new(item, discriminants, index)), } } } diff --git a/src/adapter/properties.rs b/src/adapter/properties.rs index 088fd7fe..0a65a6dd 100644 --- a/src/adapter/properties.rs +++ b/src/adapter/properties.rs @@ -566,8 +566,13 @@ pub(crate) fn resolve_discriminant_property<'a, V: AsVertex> + 'a>( property_name: &str, ) -> ContextOutcomeIterator<'a, V, FieldValue> { match property_name { - "expr" => resolve_property_with(contexts, field_property!(as_discriminant, expr)), - "value" => resolve_property_with(contexts, field_property!(as_discriminant, value)), - _ => unreachable!("AssociatedConstant property {property_name}"), + "value" => resolve_property_with(contexts, |vertex| { + vertex + .as_discriminant() + .expect("vertex was not a Discriminant") + .clone() + .into() + }), + _ => unreachable!("Discriminant property {property_name}"), } } diff --git a/src/adapter/tests.rs b/src/adapter/tests.rs index 770bc809..ea8b5bf0 100644 --- a/src/adapter/tests.rs +++ b/src/adapter/tests.rs @@ -1677,7 +1677,6 @@ fn enum_discriminants() { name @output variant { discriminant { - expr @output value @output } } @@ -1694,7 +1693,6 @@ fn enum_discriminants() { #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, serde::Deserialize)] struct Output { name: String, - expr: String, value: String, } @@ -1709,34 +1707,80 @@ fn enum_discriminants() { vec![ Output { name: "A".into(), - expr: "1".into(), + value: "0".into(), + }, + Output { + name: "A".into(), value: "1".into(), }, Output { name: "A".into(), - expr: "99".into(), - value: "99".into(), + value: "100".into(), + }, + Output { + name: "A".into(), + value: "2".into(), + }, + Output { + name: "A".into(), + value: "3".into(), }, Output { name: "A".into(), - expr: "{ _ }".into(), + value: "99".into(), + }, + Output { + name: "Fieldful".into(), + value: "0".into(), + }, + Output { + name: "Fieldful".into(), + value: "1".into(), + }, + Output { + name: "Fieldful".into(), value: "2".into(), }, Output { name: "Fieldful".into(), - expr: "9".into(), value: "9".into(), }, Output { name: "FieldlessWithDiscrimants".into(), - expr: "10".into(), value: "10".into(), }, Output { name: "FieldlessWithDiscrimants".into(), - expr: "20".into(), + value: "11".into(), + }, + Output { + name: "FieldlessWithDiscrimants".into(), value: "20".into(), }, + Output { + name: "FieldlessWithDiscrimants".into(), + value: "21".into(), + }, + Output { + name: "FieldlessWithDiscrimants".into(), + value: "22".into(), + }, + Output { + name: "Pathological".into(), + value: "-170141183460469231731687303715884105726".into(), + }, + Output { + name: "Pathological".into(), + value: "-170141183460469231731687303715884105727".into(), + }, + Output { + name: "Pathological".into(), + value: "-170141183460469231731687303715884105728".into(), + }, + Output { + name: "Pathological".into(), + value: "170141183460469231731687303715884105727".into(), + } ], results ); diff --git a/src/adapter/vertex.rs b/src/adapter/vertex.rs index 6a37bffb..0ccd508d 100644 --- a/src/adapter/vertex.rs +++ b/src/adapter/vertex.rs @@ -1,8 +1,8 @@ use std::rc::Rc; use rustdoc_types::{ - Abi, Constant, Crate, Discriminant, Enum, Function, Impl, Item, Module, Path, Span, Static, - Struct, Trait, Type, Union, Variant, VariantKind, + Abi, Constant, Crate, Enum, Function, Impl, Item, Module, Path, Span, Static, Struct, Trait, + Type, Union, Variant, VariantKind, }; use trustfall::provider::Typename; @@ -12,7 +12,7 @@ use crate::{ IndexedCrate, }; -use super::origin::Origin; +use super::{enum_variant::EnumVariant, origin::Origin}; #[non_exhaustive] #[derive(Debug, Clone)] @@ -36,7 +36,8 @@ pub enum VertexKind<'a> { ImplementedTrait(&'a Path, &'a Item), FunctionParameter(&'a str), FunctionAbi(&'a Abi), - Discriminant(&'a Discriminant), + Discriminant(String), + Variant(EnumVariant<'a>), } impl<'a> Typename for Vertex<'a> { @@ -44,24 +45,25 @@ impl<'a> Typename for Vertex<'a> { /// intended to fulfill resolution requests for the __typename property. #[inline] fn typename(&self) -> &'static str { - match self.kind { + match &self.kind { VertexKind::Item(item) => match &item.inner { rustdoc_types::ItemEnum::Module { .. } => "Module", rustdoc_types::ItemEnum::Struct(..) => "Struct", rustdoc_types::ItemEnum::Enum(..) => "Enum", rustdoc_types::ItemEnum::Union(..) => "Union", rustdoc_types::ItemEnum::Function(..) => "Function", - rustdoc_types::ItemEnum::Variant(variant) => match variant.kind { - VariantKind::Plain => "PlainVariant", - VariantKind::Tuple(..) => "TupleVariant", - VariantKind::Struct { .. } => "StructVariant", - }, rustdoc_types::ItemEnum::StructField(..) => "StructField", rustdoc_types::ItemEnum::Impl(..) => "Impl", rustdoc_types::ItemEnum::Trait(..) => "Trait", rustdoc_types::ItemEnum::Constant(..) => "Constant", rustdoc_types::ItemEnum::Static(..) => "Static", rustdoc_types::ItemEnum::AssocType { .. } => "AssociatedType", + // TODO: How are we even here??? + rustdoc_types::ItemEnum::Variant(variant) => match variant.kind { + VariantKind::Plain => "PlainVariant", + VariantKind::Tuple(..) => "TupleVariant", + VariantKind::Struct { .. } => "StructVariant", + }, _ => unreachable!("unexpected item.inner for item: {item:?}"), }, VertexKind::Span(..) => "Span", @@ -79,6 +81,11 @@ impl<'a> Typename for Vertex<'a> { VertexKind::FunctionParameter(..) => "FunctionParameter", VertexKind::FunctionAbi(..) => "FunctionAbi", VertexKind::Discriminant(..) => "Discriminant", + VertexKind::Variant(ev) => match ev.variant().unwrap().kind { + VariantKind::Plain => "PlainVariant", + VariantKind::Tuple(..) => "TupleVariant", + VariantKind::Struct { .. } => "StructVariant", + }, } } } @@ -167,10 +174,17 @@ impl<'a> Vertex<'a> { } pub(super) fn as_variant(&self) -> Option<&'a Variant> { - self.as_item().and_then(|item| match &item.inner { - rustdoc_types::ItemEnum::Variant(v) => Some(v), + match &self.kind { + VertexKind::Variant(variant) => variant.variant(), _ => None, - }) + } + } + + pub(super) fn as_enum_variant(&self) -> Option<&'a EnumVariant> { + match &self.kind { + VertexKind::Variant(variant) => Some(variant), + _ => None, + } } pub(super) fn as_path(&self) -> Option<&'a [String]> { @@ -257,9 +271,9 @@ impl<'a> Vertex<'a> { } } - pub(super) fn as_discriminant(&self) -> Option<&'a rustdoc_types::Discriminant> { + pub(super) fn as_discriminant(&self) -> Option<&String> { match &self.kind { - VertexKind::Discriminant(discriminant) => Some(discriminant), + VertexKind::Discriminant(variant) => Some(variant), _ => None, } } @@ -288,9 +302,3 @@ impl<'a> From<&'a Abi> for VertexKind<'a> { Self::FunctionAbi(a) } } - -impl<'a> From<&'a Discriminant> for VertexKind<'a> { - fn from(d: &'a Discriminant) -> Self { - Self::Discriminant(d) - } -} diff --git a/src/rustdoc_schema.graphql b/src/rustdoc_schema.graphql index 7fea71c0..15ce8511 100644 --- a/src/rustdoc_schema.graphql +++ b/src/rustdoc_schema.graphql @@ -441,13 +441,6 @@ https://docs.rs/rustdoc-types/0.28.0/rustdoc_types/struct.Discriminant.html https://doc.rust-lang.org/reference/items/enumerations.html """ type Discriminant { - """ - The expression that produced the discriminant. Preserves the original formatting seen in source code (e.g. suffixes, hexadecimal, and underscores). - - In some cases, when the value is too complex, this may be a placeholder value such as `"{ _ }"`. - """ - expr: String! - """ The numerical value of the discriminant. Stored as a string. Ranges from `i128::MIN` to `u128::MAX`. """ diff --git a/test_crates/enum_discriminants/src/lib.rs b/test_crates/enum_discriminants/src/lib.rs index eb09d0cd..154c0a2f 100644 --- a/test_crates/enum_discriminants/src/lib.rs +++ b/test_crates/enum_discriminants/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(incomplete_features)] +#![feature(repr128)] /// Some examples from #[repr(C)] @@ -27,3 +29,10 @@ pub enum Fieldful { Unit2 = 9 } +#[repr(i128)] +pub enum Pathological { + Min = i128::MIN, + MinPlusOne, + MinPlusTwo, + Max = i128::MAX, +} From c1398cd6382211bf740d282f0eed18f3acf6444b Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sun, 28 Jul 2024 09:18:36 -0400 Subject: [PATCH 09/17] remove sync structs --- src/adapter/edges.rs | 4 ++-- src/adapter/enum_variant.rs | 13 +++++++------ src/adapter/origin.rs | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/adapter/edges.rs b/src/adapter/edges.rs index b87403e3..ee05fb35 100644 --- a/src/adapter/edges.rs +++ b/src/adapter/edges.rs @@ -1,5 +1,5 @@ use rustdoc_types::{GenericBound::TraitBound, Id, ItemEnum, Variant, VariantKind}; -use std::sync::Arc; +use std::rc::Rc; use trustfall::provider::{ resolve_neighbors_with, AsVertex, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, VertexIterator, @@ -340,7 +340,7 @@ pub(super) fn resolve_enum_edge<'a, V: AsVertex> + 'a>( } }) .collect(); - Arc::new(LazyDiscriminants::new(variants)) + Rc::new(LazyDiscriminants::new(variants)) }; Box::new( diff --git a/src/adapter/enum_variant.rs b/src/adapter/enum_variant.rs index 7d33b760..d56964f1 100644 --- a/src/adapter/enum_variant.rs +++ b/src/adapter/enum_variant.rs @@ -1,14 +1,15 @@ use rustdoc_types::{Item, ItemEnum, Variant}; use std::fmt; use std::num::ParseIntError; -use std::sync::Arc; -use std::{str::FromStr, sync::OnceLock}; +use std::rc::Rc; +use std::cell::OnceCell; +use std::str::FromStr; #[non_exhaustive] #[derive(Debug, Clone)] pub(super) struct EnumVariant<'a> { item: &'a Item, - discriminants: Arc>, + discriminants: Rc>, index: usize, } @@ -16,14 +17,14 @@ pub(super) struct EnumVariant<'a> { #[derive(Debug, Clone)] pub(super) struct LazyDiscriminants<'a> { variants: Vec<&'a Variant>, - discriminants: OnceLock>, + discriminants: OnceCell>, } impl<'a> LazyDiscriminants<'a> { pub(super) fn new(variants: Vec<&'a Variant>) -> Self { Self { variants, - discriminants: OnceLock::new(), + discriminants: OnceCell::new(), } } @@ -36,7 +37,7 @@ impl<'a> LazyDiscriminants<'a> { impl<'a> EnumVariant<'a> { pub(super) fn new( item: &'a Item, - discriminants: Arc>, + discriminants: Rc>, index: usize, ) -> Self { Self { diff --git a/src/adapter/origin.rs b/src/adapter/origin.rs index 3dea1459..1728e143 100644 --- a/src/adapter/origin.rs +++ b/src/adapter/origin.rs @@ -1,4 +1,4 @@ -use std::{rc::Rc, sync::Arc}; +use std::rc::Rc; use rustdoc_types::{Abi, Item, Span}; @@ -110,7 +110,7 @@ impl Origin { pub(super) fn make_variant_vertex<'a>( &self, item: &'a Item, - discriminants: Arc>, + discriminants: Rc>, index: usize, ) -> Vertex<'a> { Vertex { From 957320e78558052c1775a7d0463ebd4bbfc26fa1 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sun, 4 Aug 2024 11:37:14 -0400 Subject: [PATCH 10/17] move to Cow<'a, str> for discriminants --- src/adapter/edges.rs | 14 ++++++++++++-- src/adapter/enum_variant.rs | 33 ++++++++++++++++++--------------- src/adapter/origin.rs | 4 ++-- src/adapter/properties.rs | 2 +- src/adapter/vertex.rs | 17 ++++++++--------- 5 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/adapter/edges.rs b/src/adapter/edges.rs index ee05fb35..05513385 100644 --- a/src/adapter/edges.rs +++ b/src/adapter/edges.rs @@ -298,9 +298,19 @@ pub(super) fn resolve_variant_edge<'a, V: AsVertex> + 'a>( }), "discriminant" => resolve_neighbors_with(contexts, move |vertex| { let origin = vertex.origin; - let enum_var = vertex.as_enum_variant().expect("vertex was not a Variant"); + // HACK: to get around closure bounds + let enum_var = match &vertex.kind { + super::VertexKind::Variant(var) => var, + _ => unreachable!("vertex was not a Variant"), + }; + let discriminant = enum_var + .discriminants + .get_discriminants() + .get(enum_var.index) + .unwrap() + .clone(); Box::new(std::iter::once( - origin.make_discriminant_vertex(enum_var.discriminant().clone()), + origin.make_discriminant_vertex(discriminant), )) }), _ => unreachable!("resolve_variant_edge {edge_name}"), diff --git a/src/adapter/enum_variant.rs b/src/adapter/enum_variant.rs index d56964f1..0fba6a13 100644 --- a/src/adapter/enum_variant.rs +++ b/src/adapter/enum_variant.rs @@ -1,23 +1,25 @@ use rustdoc_types::{Item, ItemEnum, Variant}; +use std::borrow::Cow; +use std::cell::OnceCell; use std::fmt; use std::num::ParseIntError; use std::rc::Rc; -use std::cell::OnceCell; use std::str::FromStr; #[non_exhaustive] #[derive(Debug, Clone)] pub(super) struct EnumVariant<'a> { item: &'a Item, - discriminants: Rc>, - index: usize, + // HACK: to get around closure bounds seen in ./edges.rs:301 + pub(super) discriminants: Rc>, + pub(super) index: usize, } #[non_exhaustive] #[derive(Debug, Clone)] pub(super) struct LazyDiscriminants<'a> { variants: Vec<&'a Variant>, - discriminants: OnceCell>, + discriminants: OnceCell>>, } impl<'a> LazyDiscriminants<'a> { @@ -28,7 +30,7 @@ impl<'a> LazyDiscriminants<'a> { } } - pub(super) fn get_discriminants(&self) -> &Vec { + pub(super) fn get_discriminants(&self) -> &Vec> { self.discriminants .get_or_init(|| assign_discriminants(&self.variants)) } @@ -54,12 +56,13 @@ impl<'a> EnumVariant<'a> { } } - pub(super) fn discriminant(&'a self) -> &'a String { - self.discriminants - .get_discriminants() - .get(self.index) - .unwrap() - } + // HACK: to get around closure bounds seen in ./edges.rs:301 + // pub(super) fn discriminant(&'a self) -> &'a Cow<'a, str> { + // self.discriminants + // .get_discriminants() + // .get(self.index) + // .unwrap() + // } } enum DiscriminantValue { @@ -161,16 +164,16 @@ impl FromStr for DiscriminantValue { } /// -pub(super) fn assign_discriminants(variants: &Vec<&Variant>) -> Vec { +pub(super) fn assign_discriminants<'a>(variants: &Vec<&'a Variant>) -> Vec> { let mut last: DiscriminantValue = DiscriminantValue::I64(0); - let mut discriminants: Vec = Vec::with_capacity(variants.len()); + let mut discriminants: Vec> = Vec::with_capacity(variants.len()); for v in variants { discriminants.push(match &v.discriminant { Some(d) => { last = DiscriminantValue::from_str(&d.value).unwrap(); - d.value.clone() + Cow::Borrowed(&d.value) } - None => last.to_string(), + None => Cow::Owned(last.to_string()), }); if !last.max() { last = last.increment(); diff --git a/src/adapter/origin.rs b/src/adapter/origin.rs index 1728e143..71219e06 100644 --- a/src/adapter/origin.rs +++ b/src/adapter/origin.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::{borrow::Cow, rc::Rc}; use rustdoc_types::{Abi, Item, Span}; @@ -100,7 +100,7 @@ impl Origin { } } - pub(super) fn make_discriminant_vertex<'a>(&self, value: String) -> Vertex<'a> { + pub(super) fn make_discriminant_vertex<'a>(&self, value: Cow<'a, str>) -> Vertex<'a> { Vertex { origin: *self, kind: VertexKind::Discriminant(value), diff --git a/src/adapter/properties.rs b/src/adapter/properties.rs index 0a65a6dd..893683f7 100644 --- a/src/adapter/properties.rs +++ b/src/adapter/properties.rs @@ -570,7 +570,7 @@ pub(crate) fn resolve_discriminant_property<'a, V: AsVertex> + 'a>( vertex .as_discriminant() .expect("vertex was not a Discriminant") - .clone() + .to_string() .into() }), _ => unreachable!("Discriminant property {property_name}"), diff --git a/src/adapter/vertex.rs b/src/adapter/vertex.rs index 0ccd508d..77486152 100644 --- a/src/adapter/vertex.rs +++ b/src/adapter/vertex.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::{borrow::Cow, rc::Rc}; use rustdoc_types::{ Abi, Constant, Crate, Enum, Function, Impl, Item, Module, Path, Span, Static, Struct, Trait, @@ -36,7 +36,7 @@ pub enum VertexKind<'a> { ImplementedTrait(&'a Path, &'a Item), FunctionParameter(&'a str), FunctionAbi(&'a Abi), - Discriminant(String), + Discriminant(Cow<'a, str>), Variant(EnumVariant<'a>), } @@ -52,18 +52,17 @@ impl<'a> Typename for Vertex<'a> { rustdoc_types::ItemEnum::Enum(..) => "Enum", rustdoc_types::ItemEnum::Union(..) => "Union", rustdoc_types::ItemEnum::Function(..) => "Function", + rustdoc_types::ItemEnum::Variant(variant) => match variant.kind { + VariantKind::Plain => "PlainVariant", + VariantKind::Tuple(..) => "TupleVariant", + VariantKind::Struct { .. } => "StructVariant", + }, rustdoc_types::ItemEnum::StructField(..) => "StructField", rustdoc_types::ItemEnum::Impl(..) => "Impl", rustdoc_types::ItemEnum::Trait(..) => "Trait", rustdoc_types::ItemEnum::Constant(..) => "Constant", rustdoc_types::ItemEnum::Static(..) => "Static", rustdoc_types::ItemEnum::AssocType { .. } => "AssociatedType", - // TODO: How are we even here??? - rustdoc_types::ItemEnum::Variant(variant) => match variant.kind { - VariantKind::Plain => "PlainVariant", - VariantKind::Tuple(..) => "TupleVariant", - VariantKind::Struct { .. } => "StructVariant", - }, _ => unreachable!("unexpected item.inner for item: {item:?}"), }, VertexKind::Span(..) => "Span", @@ -271,7 +270,7 @@ impl<'a> Vertex<'a> { } } - pub(super) fn as_discriminant(&self) -> Option<&String> { + pub(super) fn as_discriminant(&self) -> Option<&Cow<'a, str>> { match &self.kind { VertexKind::Discriminant(variant) => Some(variant), _ => None, From e2c3eb94d08939427a8b74eade2dc25bd4429c83 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Thu, 29 Aug 2024 17:39:17 -0400 Subject: [PATCH 11/17] Various clean-ups, still fighting closure bounds *sigh* error[E0521]: borrowed data escapes outside of closure --> src/adapter/edges.rs:304:28 | 260 | pub(super) fn resolve_variant_edge<'a, V: AsVertex> + 'a>( | -- lifetime `'a` defined here ... 302 | "discriminant" => resolve_neighbors_with(contexts, move |vertex: &'_ Vertex<'a>| { | ------ - let's call the lifetime of this reference `'1` | | | `vertex` is a reference that is only valid in the closure body 303 | let origin = vertex.origin; 304 | let enum_var = vertex | ____________________________^ 305 | | .as_variant() | | ^ | | | | |_____________________________`vertex` escapes the closure body here | argument requires that `'1` must outlive `'a` --- src/adapter/edges.rs | 31 +++++++++----------- src/adapter/enum_variant.rs | 58 +++++++++++++++++++++++-------------- src/adapter/vertex.rs | 11 ++----- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/adapter/edges.rs b/src/adapter/edges.rs index 05513385..ae57eed0 100644 --- a/src/adapter/edges.rs +++ b/src/adapter/edges.rs @@ -1,4 +1,4 @@ -use rustdoc_types::{GenericBound::TraitBound, Id, ItemEnum, Variant, VariantKind}; +use rustdoc_types::{GenericBound::TraitBound, Id, ItemEnum, VariantKind}; use std::rc::Rc; use trustfall::provider::{ resolve_neighbors_with, AsVertex, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, @@ -266,7 +266,10 @@ pub(super) fn resolve_variant_edge<'a, V: AsVertex> + 'a>( match edge_name { "field" => resolve_neighbors_with(contexts, move |vertex| { let origin = vertex.origin; - let item = vertex.as_variant().expect("vertex was not a Variant"); + let item = vertex + .as_variant() + .expect("vertex was not a Variant") + .variant(); let item_index = match origin { Origin::CurrentCrate => ¤t_crate.inner.index, Origin::PreviousCrate => { @@ -296,21 +299,14 @@ pub(super) fn resolve_variant_edge<'a, V: AsVertex> + 'a>( })), } }), - "discriminant" => resolve_neighbors_with(contexts, move |vertex| { + "discriminant" => resolve_neighbors_with(contexts, move |vertex: &'_ Vertex<'a>| { let origin = vertex.origin; - // HACK: to get around closure bounds - let enum_var = match &vertex.kind { - super::VertexKind::Variant(var) => var, - _ => unreachable!("vertex was not a Variant"), - }; - let discriminant = enum_var - .discriminants - .get_discriminants() - .get(enum_var.index) - .unwrap() - .clone(); + let enum_var = vertex + .as_variant() + .expect("vertex was not a Variant"); + let discriminant = enum_var.discriminant(); Box::new(std::iter::once( - origin.make_discriminant_vertex(discriminant), + origin.make_discriminant_vertex(std::borrow::Cow::Borrowed(discriminant)), )) }), _ => unreachable!("resolve_variant_edge {edge_name}"), @@ -339,7 +335,8 @@ pub(super) fn resolve_enum_edge<'a, V: AsVertex> + 'a>( }; let discriminants = { - let variants: Vec<&Variant> = enum_item + let len = enum_item.variants.len(); + let variants = enum_item .variants .iter() .map(move |field_id| { @@ -350,7 +347,7 @@ pub(super) fn resolve_enum_edge<'a, V: AsVertex> + 'a>( } }) .collect(); - Rc::new(LazyDiscriminants::new(variants)) + Rc::new(LazyDiscriminants::new(variants, len)) }; Box::new( diff --git a/src/adapter/enum_variant.rs b/src/adapter/enum_variant.rs index 0fba6a13..bb89f5db 100644 --- a/src/adapter/enum_variant.rs +++ b/src/adapter/enum_variant.rs @@ -1,38 +1,48 @@ use rustdoc_types::{Item, ItemEnum, Variant}; use std::borrow::Cow; use std::cell::OnceCell; -use std::fmt; +use std::fmt::{self, Debug}; use std::num::ParseIntError; use std::rc::Rc; use std::str::FromStr; #[non_exhaustive] #[derive(Debug, Clone)] -pub(super) struct EnumVariant<'a> { +pub struct EnumVariant<'a> { item: &'a Item, - // HACK: to get around closure bounds seen in ./edges.rs:301 - pub(super) discriminants: Rc>, - pub(super) index: usize, + discriminants: Rc>, + index: usize, } #[non_exhaustive] -#[derive(Debug, Clone)] pub(super) struct LazyDiscriminants<'a> { variants: Vec<&'a Variant>, discriminants: OnceCell>>, + len: usize, +} + +impl<'a> Debug for LazyDiscriminants<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f + .debug_struct("LazyDiscriminants") + .field("discriminants", &self.discriminants) + .field("len", &self.len) + .finish_non_exhaustive() + } } impl<'a> LazyDiscriminants<'a> { - pub(super) fn new(variants: Vec<&'a Variant>) -> Self { + pub(super) fn new(variants: Vec<&'a Variant>, len: usize) -> Self { Self { variants, discriminants: OnceCell::new(), + len, } } pub(super) fn get_discriminants(&self) -> &Vec> { self.discriminants - .get_or_init(|| assign_discriminants(&self.variants)) + .get_or_init(|| assign_discriminants(&self.variants, self.len)) } } @@ -49,20 +59,24 @@ impl<'a> EnumVariant<'a> { } } - pub(super) fn variant(&self) -> Option<&'a Variant> { + pub(super) fn variant(&self) -> &'a Variant { match &self.item.inner { - ItemEnum::Variant(v) => Some(v), - _ => None, + ItemEnum::Variant(v) => v, + _ => unreachable!("Item was not a Variant"), } } - // HACK: to get around closure bounds seen in ./edges.rs:301 - // pub(super) fn discriminant(&'a self) -> &'a Cow<'a, str> { - // self.discriminants - // .get_discriminants() - // .get(self.index) - // .unwrap() - // } + pub(super) fn discriminant(&'a self) -> &'a Cow<'a, str> { + self.discriminants + .get_discriminants() + .get(self.index) + .expect("self.index should exist in self.discriminants") + } + + #[inline] + pub(super) fn item(&self) -> &'a Item { + self.item + } } enum DiscriminantValue { @@ -164,9 +178,9 @@ impl FromStr for DiscriminantValue { } /// -pub(super) fn assign_discriminants<'a>(variants: &Vec<&'a Variant>) -> Vec> { +pub(super) fn assign_discriminants<'a>(variants: &Vec<&'a Variant>, len: usize) -> Vec> { let mut last: DiscriminantValue = DiscriminantValue::I64(0); - let mut discriminants: Vec> = Vec::with_capacity(variants.len()); + let mut discriminants: Vec> = Vec::with_capacity(len); for v in variants { discriminants.push(match &v.discriminant { Some(d) => { @@ -232,7 +246,7 @@ mod tests { kind: VariantKind::Plain, }, ]; - let actual = assign_discriminants(&variants); + let actual = assign_discriminants(&variants, variants.len()); let expected: Vec = vec![ "0".into(), "1".into(), @@ -293,7 +307,7 @@ mod tests { }, &explicit_4, ]; - let actual = assign_discriminants(&variants); + let actual = assign_discriminants(&variants, variants.len()); let expected: Vec = vec![ "9223372036854775807".into(), "9223372036854775808".into(), diff --git a/src/adapter/vertex.rs b/src/adapter/vertex.rs index 77486152..e456f3b8 100644 --- a/src/adapter/vertex.rs +++ b/src/adapter/vertex.rs @@ -80,7 +80,7 @@ impl<'a> Typename for Vertex<'a> { VertexKind::FunctionParameter(..) => "FunctionParameter", VertexKind::FunctionAbi(..) => "FunctionAbi", VertexKind::Discriminant(..) => "Discriminant", - VertexKind::Variant(ev) => match ev.variant().unwrap().kind { + VertexKind::Variant(ev) => match ev.variant().kind { VariantKind::Plain => "PlainVariant", VariantKind::Tuple(..) => "TupleVariant", VariantKind::Struct { .. } => "StructVariant", @@ -172,14 +172,7 @@ impl<'a> Vertex<'a> { }) } - pub(super) fn as_variant(&self) -> Option<&'a Variant> { - match &self.kind { - VertexKind::Variant(variant) => variant.variant(), - _ => None, - } - } - - pub(super) fn as_enum_variant(&self) -> Option<&'a EnumVariant> { + pub(super) fn as_variant(&self) -> Option<&'_ EnumVariant<'a>> { match &self.kind { VertexKind::Variant(variant) => Some(variant), _ => None, From b6b77238bd1dac44f7375adf6f9e245550f7f605 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Thu, 29 Aug 2024 18:49:54 -0400 Subject: [PATCH 12/17] Actually clone Cow; same error as before, though... --- src/adapter/edges.rs | 2 +- src/adapter/enum_variant.rs | 3 ++- src/adapter/vertex.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/adapter/edges.rs b/src/adapter/edges.rs index ae57eed0..9e3d3af6 100644 --- a/src/adapter/edges.rs +++ b/src/adapter/edges.rs @@ -306,7 +306,7 @@ pub(super) fn resolve_variant_edge<'a, V: AsVertex> + 'a>( .expect("vertex was not a Variant"); let discriminant = enum_var.discriminant(); Box::new(std::iter::once( - origin.make_discriminant_vertex(std::borrow::Cow::Borrowed(discriminant)), + origin.make_discriminant_vertex(discriminant), )) }), _ => unreachable!("resolve_variant_edge {edge_name}"), diff --git a/src/adapter/enum_variant.rs b/src/adapter/enum_variant.rs index bb89f5db..37c8b608 100644 --- a/src/adapter/enum_variant.rs +++ b/src/adapter/enum_variant.rs @@ -66,11 +66,12 @@ impl<'a> EnumVariant<'a> { } } - pub(super) fn discriminant(&'a self) -> &'a Cow<'a, str> { + pub(super) fn discriminant(&'a self) -> Cow<'a, str> { self.discriminants .get_discriminants() .get(self.index) .expect("self.index should exist in self.discriminants") + .clone() } #[inline] diff --git a/src/adapter/vertex.rs b/src/adapter/vertex.rs index e456f3b8..28d53626 100644 --- a/src/adapter/vertex.rs +++ b/src/adapter/vertex.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, rc::Rc}; use rustdoc_types::{ Abi, Constant, Crate, Enum, Function, Impl, Item, Module, Path, Span, Static, Struct, Trait, - Type, Union, Variant, VariantKind, + Type, Union, VariantKind, }; use trustfall::provider::Typename; From ef7d9a390b976971737405ab357490ee5932b996 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Thu, 29 Aug 2024 19:03:13 -0400 Subject: [PATCH 13/17] Got the sucker. --- src/adapter/enum_variant.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adapter/enum_variant.rs b/src/adapter/enum_variant.rs index 37c8b608..9d26d29a 100644 --- a/src/adapter/enum_variant.rs +++ b/src/adapter/enum_variant.rs @@ -66,7 +66,7 @@ impl<'a> EnumVariant<'a> { } } - pub(super) fn discriminant(&'a self) -> Cow<'a, str> { + pub(super) fn discriminant(&self) -> Cow<'a, str> { self.discriminants .get_discriminants() .get(self.index) From 836b5f56df3d23ded1e3437c56f7100b57424153 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sat, 31 Aug 2024 14:41:09 -0400 Subject: [PATCH 14/17] Wrap up --- src/adapter/edges.rs | 7 ++----- src/adapter/enum_variant.rs | 19 ++++++++----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/adapter/edges.rs b/src/adapter/edges.rs index 9e3d3af6..84dae80e 100644 --- a/src/adapter/edges.rs +++ b/src/adapter/edges.rs @@ -301,9 +301,7 @@ pub(super) fn resolve_variant_edge<'a, V: AsVertex> + 'a>( }), "discriminant" => resolve_neighbors_with(contexts, move |vertex: &'_ Vertex<'a>| { let origin = vertex.origin; - let enum_var = vertex - .as_variant() - .expect("vertex was not a Variant"); + let enum_var = vertex.as_variant().expect("vertex was not a Variant"); let discriminant = enum_var.discriminant(); Box::new(std::iter::once( origin.make_discriminant_vertex(discriminant), @@ -335,7 +333,6 @@ pub(super) fn resolve_enum_edge<'a, V: AsVertex> + 'a>( }; let discriminants = { - let len = enum_item.variants.len(); let variants = enum_item .variants .iter() @@ -347,7 +344,7 @@ pub(super) fn resolve_enum_edge<'a, V: AsVertex> + 'a>( } }) .collect(); - Rc::new(LazyDiscriminants::new(variants, len)) + Rc::new(LazyDiscriminants::new(variants)) }; Box::new( diff --git a/src/adapter/enum_variant.rs b/src/adapter/enum_variant.rs index 9d26d29a..b65e7ce5 100644 --- a/src/adapter/enum_variant.rs +++ b/src/adapter/enum_variant.rs @@ -16,33 +16,30 @@ pub struct EnumVariant<'a> { #[non_exhaustive] pub(super) struct LazyDiscriminants<'a> { + // TODO: Consider replacing Vec with an impl Iterator for performance variants: Vec<&'a Variant>, discriminants: OnceCell>>, - len: usize, } impl<'a> Debug for LazyDiscriminants<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f - .debug_struct("LazyDiscriminants") + f.debug_struct("LazyDiscriminants") .field("discriminants", &self.discriminants) - .field("len", &self.len) .finish_non_exhaustive() } } impl<'a> LazyDiscriminants<'a> { - pub(super) fn new(variants: Vec<&'a Variant>, len: usize) -> Self { + pub(super) fn new(variants: Vec<&'a Variant>) -> Self { Self { variants, discriminants: OnceCell::new(), - len, } } pub(super) fn get_discriminants(&self) -> &Vec> { self.discriminants - .get_or_init(|| assign_discriminants(&self.variants, self.len)) + .get_or_init(|| assign_discriminants(&self.variants)) } } @@ -179,9 +176,9 @@ impl FromStr for DiscriminantValue { } /// -pub(super) fn assign_discriminants<'a>(variants: &Vec<&'a Variant>, len: usize) -> Vec> { +pub(super) fn assign_discriminants<'a>(variants: &[&'a Variant]) -> Vec> { let mut last: DiscriminantValue = DiscriminantValue::I64(0); - let mut discriminants: Vec> = Vec::with_capacity(len); + let mut discriminants: Vec> = Vec::with_capacity(variants.len()); for v in variants { discriminants.push(match &v.discriminant { Some(d) => { @@ -247,7 +244,7 @@ mod tests { kind: VariantKind::Plain, }, ]; - let actual = assign_discriminants(&variants, variants.len()); + let actual = assign_discriminants(&variants); let expected: Vec = vec![ "0".into(), "1".into(), @@ -308,7 +305,7 @@ mod tests { }, &explicit_4, ]; - let actual = assign_discriminants(&variants, variants.len()); + let actual = assign_discriminants(&variants); let expected: Vec = vec![ "9223372036854775807".into(), "9223372036854775808".into(), From 9ace8655d085761de39879264af3f3a3bb3e1282 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sun, 1 Sep 2024 11:11:18 -0400 Subject: [PATCH 15/17] Better dcocs for discriminant Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> --- src/rustdoc_schema.graphql | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/rustdoc_schema.graphql b/src/rustdoc_schema.graphql index 15ce8511..6493ba61 100644 --- a/src/rustdoc_schema.graphql +++ b/src/rustdoc_schema.graphql @@ -431,7 +431,22 @@ interface Variant implements Item { field: [StructField!] """ - The discriminant, if explicitly specified. + The discriminant value of this variant, if its value is well-defined. + + A discriminant is an integer value that is logically associated with an enum variant, + and is used to determine which variant an enum value holds. + + Discriminant values are not always well-defined. + + In order for variants to have well-defined discriminants, their enum must either + - define a primitive representation (e.g., `#[repr(u8)]`), or + - be "unit-only" i.e. consisting solely of unit variants. + + The variants of such enums may be explicitly assigned a discriminant value, or + the discriminant may be defined implicitly: + - The first variant has a discriminant of zero, unless explicitly assigned a value. + - Subsequent variants have a discriminant one higher than the previous variant, + unless explicitly assigned a value. """ discriminant: Discriminant } From c164df6e138faacd24639eb3d3188fd0fbed9e71 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sun, 1 Sep 2024 11:58:55 -0400 Subject: [PATCH 16/17] Finish up docs, improve tests --- src/adapter/tests.rs | 122 ++++++++++++++-------- src/adapter/vertex.rs | 3 +- src/rustdoc_schema.graphql | 57 ++++++++++ test_crates/enum_discriminants/src/lib.rs | 6 ++ 4 files changed, 144 insertions(+), 44 deletions(-) diff --git a/src/adapter/tests.rs b/src/adapter/tests.rs index ea8b5bf0..4721fbf4 100644 --- a/src/adapter/tests.rs +++ b/src/adapter/tests.rs @@ -1674,9 +1674,10 @@ fn enum_discriminants() { Crate { item { ... on Enum { - name @output + enum_name: name @output variant { - discriminant { + variant_name: name @output + discriminant @optional { value @output } } @@ -1692,8 +1693,9 @@ fn enum_discriminants() { #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, serde::Deserialize)] struct Output { - name: String, - value: String, + enum_name: String, + variant_name: String, + value: Option, } let mut results: Vec = @@ -1706,81 +1708,115 @@ fn enum_discriminants() { similar_asserts::assert_eq!( vec![ Output { - name: "A".into(), - value: "0".into(), + enum_name: "A".into(), + variant_name: "Five".into(), + value: Some("100".into(),), }, Output { - name: "A".into(), - value: "1".into(), + enum_name: "A".into(), + variant_name: "Four".into(), + value: Some("99".into(),), }, Output { - name: "A".into(), - value: "100".into(), + enum_name: "A".into(), + variant_name: "One".into(), + value: Some("1".into(),), }, Output { - name: "A".into(), - value: "2".into(), + enum_name: "A".into(), + variant_name: "Three".into(), + value: Some("3".into(),), }, Output { - name: "A".into(), - value: "3".into(), + enum_name: "A".into(), + variant_name: "Two".into(), + value: Some("2".into(),), }, Output { - name: "A".into(), - value: "99".into(), + enum_name: "A".into(), + variant_name: "Zero".into(), + value: Some("0".into(),), }, Output { - name: "Fieldful".into(), - value: "0".into(), + enum_name: "Fieldful".into(), + variant_name: "Struct".into(), + value: Some("2".into(),), }, Output { - name: "Fieldful".into(), - value: "1".into(), + enum_name: "Fieldful".into(), + variant_name: "Tuple".into(), + value: Some("1".into(),), }, Output { - name: "Fieldful".into(), - value: "2".into(), + enum_name: "Fieldful".into(), + variant_name: "Unit".into(), + value: Some("0".into(),), }, Output { - name: "Fieldful".into(), - value: "9".into(), + enum_name: "Fieldful".into(), + variant_name: "Unit2".into(), + value: Some("9".into(),), }, Output { - name: "FieldlessWithDiscrimants".into(), - value: "10".into(), + enum_name: "FieldfulNoRepr".into(), + variant_name: "Struct".into(), + value: Some("2".into(),), }, Output { - name: "FieldlessWithDiscrimants".into(), - value: "11".into(), + enum_name: "FieldfulNoRepr".into(), + variant_name: "Tuple".into(), + value: Some("1".into(),), }, Output { - name: "FieldlessWithDiscrimants".into(), - value: "20".into(), + enum_name: "FieldfulNoRepr".into(), + variant_name: "Unit".into(), + value: Some("0".into(),), }, Output { - name: "FieldlessWithDiscrimants".into(), - value: "21".into(), + enum_name: "FieldlessWithDiscrimants".into(), + variant_name: "First".into(), + value: Some("10".into(),), }, Output { - name: "FieldlessWithDiscrimants".into(), - value: "22".into(), + enum_name: "FieldlessWithDiscrimants".into(), + variant_name: "Second".into(), + value: Some("20".into(),), }, Output { - name: "Pathological".into(), - value: "-170141183460469231731687303715884105726".into(), + enum_name: "FieldlessWithDiscrimants".into(), + variant_name: "Struct".into(), + value: Some("21".into(),), }, Output { - name: "Pathological".into(), - value: "-170141183460469231731687303715884105727".into(), + enum_name: "FieldlessWithDiscrimants".into(), + variant_name: "Tuple".into(), + value: Some("11".into(),), }, Output { - name: "Pathological".into(), - value: "-170141183460469231731687303715884105728".into(), + enum_name: "FieldlessWithDiscrimants".into(), + variant_name: "Unit".into(), + value: Some("22".into(),), }, Output { - name: "Pathological".into(), - value: "170141183460469231731687303715884105727".into(), - } + enum_name: "Pathological".into(), + variant_name: "Max".into(), + value: Some("170141183460469231731687303715884105727".into(),), + }, + Output { + enum_name: "Pathological".into(), + variant_name: "Min".into(), + value: Some("-170141183460469231731687303715884105728".into(),), + }, + Output { + enum_name: "Pathological".into(), + variant_name: "MinPlusOne".into(), + value: Some("-170141183460469231731687303715884105727".into(),), + }, + Output { + enum_name: "Pathological".into(), + variant_name: "MinPlusTwo".into(), + value: Some("-170141183460469231731687303715884105726".into(),), + }, ], results ); diff --git a/src/adapter/vertex.rs b/src/adapter/vertex.rs index 28d53626..6596db31 100644 --- a/src/adapter/vertex.rs +++ b/src/adapter/vertex.rs @@ -117,8 +117,9 @@ impl<'a> Vertex<'a> { } pub(super) fn as_item(&self) -> Option<&'a Item> { - match self.kind { + match &self.kind { VertexKind::Item(item) => Some(item), + VertexKind::Variant(variant) => Some(variant.item()), _ => None, } } diff --git a/src/rustdoc_schema.graphql b/src/rustdoc_schema.graphql index 6493ba61..bf19e5a3 100644 --- a/src/rustdoc_schema.graphql +++ b/src/rustdoc_schema.graphql @@ -514,6 +514,25 @@ type PlainVariant implements Item & Variant { # edges from Variant field: [StructField!] + + """ + The discriminant value of this variant, if its value is well-defined. + + A discriminant is an integer value that is logically associated with an enum variant, + and is used to determine which variant an enum value holds. + + Discriminant values are not always well-defined. + + In order for variants to have well-defined discriminants, their enum must either + - define a primitive representation (e.g., `#[repr(u8)]`), or + - be "unit-only" i.e. consisting solely of unit variants. + + The variants of such enums may be explicitly assigned a discriminant value, or + the discriminant may be defined implicitly: + - The first variant has a discriminant of zero, unless explicitly assigned a value. + - Subsequent variants have a discriminant one higher than the previous variant, + unless explicitly assigned a value. + """ discriminant: Discriminant } @@ -569,6 +588,25 @@ type TupleVariant implements Item & Variant { # edges from Variant field: [StructField!] + + """ + The discriminant value of this variant, if its value is well-defined. + + A discriminant is an integer value that is logically associated with an enum variant, + and is used to determine which variant an enum value holds. + + Discriminant values are not always well-defined. + + In order for variants to have well-defined discriminants, their enum must either + - define a primitive representation (e.g., `#[repr(u8)]`), or + - be "unit-only" i.e. consisting solely of unit variants. + + The variants of such enums may be explicitly assigned a discriminant value, or + the discriminant may be defined implicitly: + - The first variant has a discriminant of zero, unless explicitly assigned a value. + - Subsequent variants have a discriminant one higher than the previous variant, + unless explicitly assigned a value. + """ discriminant: Discriminant } @@ -624,6 +662,25 @@ type StructVariant implements Item & Variant { # edges from Variant field: [StructField!] + + """ + The discriminant value of this variant, if its value is well-defined. + + A discriminant is an integer value that is logically associated with an enum variant, + and is used to determine which variant an enum value holds. + + Discriminant values are not always well-defined. + + In order for variants to have well-defined discriminants, their enum must either + - define a primitive representation (e.g., `#[repr(u8)]`), or + - be "unit-only" i.e. consisting solely of unit variants. + + The variants of such enums may be explicitly assigned a discriminant value, or + the discriminant may be defined implicitly: + - The first variant has a discriminant of zero, unless explicitly assigned a value. + - Subsequent variants have a discriminant one higher than the previous variant, + unless explicitly assigned a value. + """ discriminant: Discriminant } diff --git a/test_crates/enum_discriminants/src/lib.rs b/test_crates/enum_discriminants/src/lib.rs index 154c0a2f..faafcbec 100644 --- a/test_crates/enum_discriminants/src/lib.rs +++ b/test_crates/enum_discriminants/src/lib.rs @@ -29,6 +29,12 @@ pub enum Fieldful { Unit2 = 9 } +pub enum FieldfulNoRepr { + Unit, + Tuple(bool), + Struct{a: bool}, +} + #[repr(i128)] pub enum Pathological { Min = i128::MIN, From e7aa5f37228fab51f65b22d85801ba59141cd120 Mon Sep 17 00:00:00 2001 From: Kyle Anthony Williams Date: Sun, 1 Sep 2024 12:22:07 -0400 Subject: [PATCH 17/17] Add name back. --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58dc82a3..d2f83e4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,3 +1,5 @@ +name: CI + on: pull_request: push: