Skip to content

Commit

Permalink
Add Constant type/value properties (#280)
Browse files Browse the repository at this point in the history
* add Constant property resolution function

allow reading constant value/expr/is_literal and type (this one serialized to a json string since there is no impl to convert it to FieldValue)

* add Constant property rustdocs example

* add Constant property rustdoc schema

* dep: add serde_json for Constant property Type

* fix clippy

* uglify with rustfmt

* Update src/rustdoc_schema.graphql

Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com>

* squeeze doc comment

* add a doc comment note referencing a more comprehensive example

to avoid repeating said example

* add type_ field to AssociatedConstant property resolution function

(temporary in the json string format)

* add type_ field to AssociatedConstant property rustdoc schema

* split schema docs so that each Constant property is documented

* update schema doc comment

* update schema docs trait name

* fix a typo in schema docs

* remove type Assoc/Const property

until trustfall adds proper support for custom scalar types

* remove type Assoc/Const property from schema

* fix a typo in schema docs

Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com>

* dep: remove serde_json since Constant property Type was removed

Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com>

* remove unstable rustdocs example for Constant properties

Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com>

* Update formatting of the schema docs

Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com>

* Update AssociatedConstant example to refer to a const generic

* Update Constant test with extra properties

expr/value/is_literal

---------

Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com>
  • Loading branch information
eugenesvk and obi1kenobi committed Oct 9, 2023
1 parent e109e74 commit f9455eb
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 13 deletions.
1 change: 1 addition & 0 deletions src/adapter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ impl<'a> Adapter<'a> for RustdocAdapter<'a> {
"AssociatedConstant" => {
properties::resolve_associated_constant_property(contexts, property_name)
}
"Constant" => properties::resolve_constant_property(contexts, property_name),
_ => unreachable!("resolve_property {type_name} {property_name}"),
}
}
Expand Down
36 changes: 36 additions & 0 deletions src/adapter/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,3 +423,39 @@ pub(crate) fn resolve_associated_constant_property<'a>(
_ => unreachable!("AssociatedConstant property {property_name}"),
}
}

pub(crate) fn resolve_constant_property<'a>(
contexts: ContextIterator<'a, Vertex<'a>>,
property_name: &str,
) -> ContextOutcomeIterator<'a, Vertex<'a>, FieldValue> {
match property_name {
"expr" => resolve_property_with(
contexts,
field_property!(as_item, inner, {
let ItemEnum::Constant(c) = &inner else {
unreachable!("expected to have a Constant")
};
c.expr.clone().into()
}),
),
"value" => resolve_property_with(
contexts,
field_property!(as_item, inner, {
let ItemEnum::Constant(c) = &inner else {
unreachable!("expected to have a Constant")
};
c.value.clone().into()
}),
),
"is_literal" => resolve_property_with(
contexts,
field_property!(as_item, inner, {
let ItemEnum::Constant(c) = &inner else {
unreachable!("expected to have a Constant")
};
c.is_literal.into()
}),
),
_ => unreachable!("Constant property {property_name}"),
}
}
36 changes: 33 additions & 3 deletions src/adapter/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ fn rustdoc_finds_consts() {
item {
... on Constant {
name @output
expr @output
value @output
is_literal @output
importable_path {
path @output
Expand All @@ -190,24 +193,48 @@ fn rustdoc_finds_consts() {
struct Output {
name: String,
path: Vec<String>,
expr: String,
value: Option<String>,
is_literal: bool,
}
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, serde::Deserialize)]
struct OutputSimple {
name: String,
path: Vec<String>,
}

let mut results: Vec<_> =
trustfall::execute_query(&schema, adapter.clone(), query, variables.clone())
.expect("failed to run query")
.map(|row| row.try_into_struct().expect("shape mismatch"))
.map(|row| row.try_into_struct::<Output>().expect("shape mismatch"))
.collect();
results.sort_unstable();
// to compare to GlobalValue that doesn't Constant-specific properties
let mut results_simple: Vec<_> =
trustfall::execute_query(&schema, adapter.clone(), query, variables.clone())
.expect("failed to run query")
.map(|row| {
row.try_into_struct::<OutputSimple>()
.expect("shape mismatch")
})
.collect();
results_simple.sort_unstable();

similar_asserts::assert_eq!(
vec![
Output {
name: "FIRST".into(),
path: vec!["consts".into(), "FIRST".into()],
expr: "1".to_string(),
value: Some("1u32".to_string()),
is_literal: true,
},
Output {
name: "SECOND".into(),
path: vec!["consts".into(), "inner".into(), "SECOND".into()],
expr: "2".to_string(),
value: Some("2i64".to_string()),
is_literal: true,
},
],
results
Expand All @@ -232,10 +259,13 @@ fn rustdoc_finds_consts() {
let mut global_values_results: Vec<_> =
trustfall::execute_query(&schema, adapter, global_values_query, variables)
.expect("failed to run query")
.map(|row| row.try_into_struct().expect("shape mismatch"))
.map(|row| {
row.try_into_struct::<OutputSimple>()
.expect("shape mismatch")
})
.collect();
global_values_results.sort_unstable();
assert_eq!(results, global_values_results);
assert_eq!(results_simple, global_values_results);
}

#[test]
Expand Down
79 changes: 69 additions & 10 deletions src/rustdoc_schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,61 @@ type Constant implements Item & Importable & GlobalValue {
attrs: [String!]!
visibility_limit: String!

# properties for Constant
"""
The expression of the constant, if any, as a Rust literal or `"_"`. For example:
```rust
// // expr
const MIN : usize = 16 ; // 16
const MIN_SIZE: usize = MIN ; // "MIN", referring to the other constant's name
const LOG_AS : &str = "batch" ; // "\"batch\"", including escaped quotes
const YEAR : Years = Years(42); // "_"
const EXPR_2_2: i32 = 2 + 2 ; // "_"
const FN_FIVE : i32 = five() ; // "_"
const fn five() -> i32 { 5 };
struct Years(i32);
```
If the constant is set:
- to be equal to another constant, `expr` holds the name of that other constant.
- by evaluating a `const` expression, such as `2 + 2` or a `const fn` call, `expr` is `"_"` instead of including the full expression.
"""
expr: String
"""
The value of the constant, if any, as a Rust literal. For example:
```rust
// // value
const MIN : usize = 16 ; // "16usize"
const MIN_SIZE: usize = MIN ; // "16usize"
const LOG_AS : &str = "batch" ; // None
const YEAR : Years = Years(42); // None
const EXPR_2_2: i32 = 2 + 2 ; // "4i32"
const FN_FIVE : i32 = five() ; // "5i32"
const fn five() -> i32 { 5 };
struct Years(i32);
```
If the constant is set:
- to be equal to another constant, `value` holds the value of that other constant.
- by evaluating a `const` expression, such as `2 + 2` or a `const fn` call, `value` is evaluated
"""
value: String
"""
The literal flag of the constant. For example:
```rust
// // is_literal
const MIN : usize = 16 ; // true
const MIN_SIZE: usize = MIN ; // false
const LOG_AS : &str = "batch" ; // true
const YEAR : Years = Years(42); // false
const EXPR_2_2: i32 = 2 + 2 ; // false
const FN_FIVE : i32 = five() ; // false
const fn five() -> i32 { 5 };
struct Years(i32);
```
"""
is_literal: Boolean

# edges from Item
span: Span
attribute: [Attribute!]
Expand Down Expand Up @@ -858,21 +913,25 @@ type AssociatedConstant implements Item {
For example:
```rust
trait BatchIterator<const MIN: usize> {
const SIZE: usize = 16; // `"16"` is the default
const LOG_AS: &'static str = "batch"; // `"\"batch\""` is the default, including escaped quotes
const MIN_SIZE: usize = MIN; // "MIN" is the default, referring to the other constant's name
const fn five() -> i32 { 5 };
struct Years(i32);
trait MyTrait<const MIN: usize> { // rustdocs default field
const NUM : i32 = 16 ; // 16
const MIN_SIZE: usize = MIN ; // "MIN", referring to the other constant's name
const LOG_AS : &'static str = "batch" ; // "\"batch\"", including escaped quotes
const EXPR2_2 : i32 = 2+2 ; // "_"
const FN_FIVE : i32 = five() ; // "_"
const YEAR : Years = Years(42); // "_"
}
```
If the associated constant is on a type's inherent impl, the default is always required to be set.
If the associated constant is on a type's inherent impl, `default` is always required to be set.
If the associated constant is set to be equal to another constant, the default holds the name
of that other constant.
If the associated constant is set:
If the associated constant is set by evaluating a `const` expression, such as `2 + 2` or
a `const fn` call, rustdoc's current behavior is to show a default value of `"_"`
instead of evaluating the constant value or including the full expression.
- to be equal to another constant, `default` holds the name of that other constant.
- by evaluating a `const` expression, such as `2 + 2` or a `const fn` call,
`default` is `"_"` instead of evaluating the constant value or including the full expression.
"""
default: String

Expand Down

0 comments on commit f9455eb

Please sign in to comment.