Skip to content

Commit

Permalink
split Node into newtypes of Item, ItemSummary and ExternalCrate WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
StuartHarris committed Dec 6, 2024
1 parent b9caf63 commit 7ee1e77
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 58 deletions.
10 changes: 8 additions & 2 deletions crux_cli/src/codegen/filter.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
use ascent::ascent;

use super::node::Node;
use super::node::{Node, Summary};

ascent! {
pub struct Filter;

// ------- facts ------------------
relation node(Node);
relation summary(Summary);

// ------- rules ------------------

relation has_summary(Node, Summary);
has_summary(n, s) <-- node(n), summary(s), if n.has_summary(s);

relation is_struct(Node);
is_struct(s) <-- node(s), if s.is_struct();

Expand Down Expand Up @@ -68,7 +72,9 @@ ascent! {
is_enum(effect),
node(effect_impl),
if effect_impl.is_impl_for(effect, "Effect"),
if app.is_in_same_module_as(effect),
has_summary(app, app_summary),
has_summary(effect, effect_summary),
if app_summary.in_same_module_as(effect_summary),
type_of(effect_ffi_item, effect_ffi),
if effect_impl.has_associated_item(effect_ffi_item, "Ffi");

Expand Down
18 changes: 11 additions & 7 deletions crux_cli/src/codegen/filter_tests.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
use rustdoc_types::Crate;

use crate::codegen::parse;
use crate::codegen::node::Node;

#[test]
fn field_is_option_of_t() {
static RUSTDOC: &'static [u8] = include_bytes!("fixtures/field_is_option_of_t.json");
let crate_: Crate = serde_json::from_slice(RUSTDOC).unwrap();
let nodes = parse(crate_);

let mut prog = super::Filter::default();
prog.node = nodes;
prog.node = crate_
.index
.values()
.map(|item| {
(Node {
id: item.id,
item: Some(item.clone()),
},)
})
.collect::<Vec<_>>();
prog.run();

// 345 (struct: ViewModel) to 343 (field: image)
Expand Down Expand Up @@ -68,7 +76,6 @@ fn field_is_option_of_t() {
),
},
),
summary: None,
},
Node {
id: Id(
Expand Down Expand Up @@ -136,7 +143,6 @@ fn field_is_option_of_t() {
),
},
),
summary: None,
},
),
]
Expand Down Expand Up @@ -214,7 +220,6 @@ fn field_is_option_of_t() {
),
},
),
summary: None,
},
Node {
id: Id(
Expand Down Expand Up @@ -348,7 +353,6 @@ fn field_is_option_of_t() {
),
},
),
summary: None,
},
),
]
Expand Down
44 changes: 27 additions & 17 deletions crux_cli/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustdoc_types::Crate;
use crate::args::CodegenArgs;
use filter::Filter;
use formatter::Formatter;
use node::Node;
use node::{Node, Summary};
use serde_generate::format::ContainerFormat;

pub type Registry = BTreeMap<String, ContainerFormat>;
Expand All @@ -35,38 +35,48 @@ pub fn codegen(args: &CodegenArgs) -> Result<()> {
let file = File::open(json_path)?;
let crate_: Crate = serde_json::from_reader(file)?;

let nodes = parse(crate_);
let manifest_paths: BTreeMap<&str, &str> = package_graph
.packages()
.map(|package| (package.name(), package.manifest_path().as_str()))
.collect();

let registry = run(nodes);
println!("{:#?}", manifest_paths);

let registry = run(crate_);

println!("{:#?}", registry);

Ok(())
}

fn run(nodes: Vec<(Node,)>) -> Registry {
fn run(crate_: Crate) -> Registry {
let mut filter = Filter::default();
filter.node = nodes;
filter.run();

let mut formatter = Formatter::default();
formatter.edge = filter.edge;
formatter.run();
formatter.container.into_iter().collect()
}

fn parse(crate_: Crate) -> Vec<(Node,)> {
crate_
filter.summary = crate_
.paths
.iter()
.map(|(id, summary)| {
(Summary {
id: *id,
summary: summary.clone(),
},)
})
.collect::<Vec<_>>();
filter.node = crate_
.index
.values()
.map(|item| {
(Node {
id: item.id,
item: Some(item.clone()),
summary: crate_.paths.get(&item.id).cloned(),
},)
})
.collect::<Vec<_>>()
.collect::<Vec<_>>();
filter.run();

let mut formatter = Formatter::default();
formatter.edge = filter.edge;
formatter.run();
formatter.container.into_iter().collect()
}

#[cfg(test)]
Expand Down
83 changes: 62 additions & 21 deletions crux_cli/src/codegen/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,34 @@ use rustdoc_types::{
};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct Summary {
pub id: Id,
pub summary: ItemSummary,
}

impl Summary {
pub fn in_same_module_as(&self, other: &Summary) -> bool {
let this = &self.summary.path;
let other = &other.summary.path;

if this.len() != other.len() {
return false;
};

this[..(this.len() - 1)] == other[..(other.len() - 1)]
}
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Node {
pub id: Id,
pub item: Option<Item>,
pub summary: Option<ItemSummary>,
}

impl Hash for Node {
fn hash<H: Hasher>(&self, state: &mut H) {
let crate_id = self.summary.as_ref().map(|s| &s.crate_id);
let crate_id = self.item.as_ref().map(|i| &i.crate_id);
(crate_id, self.id).hash(state);
}
}
Expand All @@ -39,6 +57,10 @@ impl Node {
})
}

pub fn has_summary(&self, summary: &Summary) -> bool {
self.id == summary.id
}

pub fn is_struct(&self) -> bool {
matches!(
&self.item,
Expand Down Expand Up @@ -205,18 +227,6 @@ impl Node {
}
}

pub fn is_in_same_module_as(&self, other: &Node) -> bool {
let (Some(this), Some(other)) = (&self.summary, &other.summary) else {
return false;
};

if this.path.len() != other.path.len() {
return false;
};

this.path[..(this.path.len() - 1)] == other.path[..(other.path.len() - 1)]
}

pub fn index_of(&self, child: &Node) -> Option<usize> {
match &self.item {
Some(Item {
Expand Down Expand Up @@ -269,11 +279,22 @@ fn check_args(type_node: &Node, args: &Option<Box<GenericArgs>>) -> bool {
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use rustdoc_types::{Generics, Id, Item, ItemEnum, Struct, StructKind, Visibility};
use rustdoc_types::{Generics, Id, Item, ItemEnum, ItemKind, Struct, StructKind, Visibility};

use super::*;

fn test_node(name: Option<String>, attrs: Vec<String>) -> Node {
fn make_summary(id: Id, path: Vec<String>) -> Summary {
Summary {
id,
summary: ItemSummary {
crate_id: 0,
path,
kind: ItemKind::Struct,
},
}
}

fn make_node(name: Option<String>, attrs: Vec<String>) -> Node {
Node {
item: Some(Item {
name,
Expand All @@ -298,39 +319,59 @@ mod tests {
deprecation: None,
}),
id: Id(0),
summary: None,
}
}

#[test]
fn test_in_same_module_as() {
let summary1 = make_summary(Id(0), vec!["foo".to_string(), "bar".to_string()]);
let summary2 = make_summary(Id(1), vec!["foo".to_string(), "baz".to_string()]);
assert!(summary1.in_same_module_as(&summary2));
}

#[test]
fn test_in_same_module_as_different_length() {
let summary1 = make_summary(Id(0), vec!["foo".to_string(), "bar".to_string()]);
let summary2 = make_summary(Id(1), vec!["foo".to_string()]);
assert!(!summary1.in_same_module_as(&summary2));
}

#[test]
fn test_in_same_module_as_different_module() {
let summary1 = make_summary(Id(0), vec!["foo".to_string(), "bar".to_string()]);
let summary2 = make_summary(Id(1), vec!["baz".to_string(), "bar".to_string()]);
assert!(!summary1.in_same_module_as(&summary2));
}

#[test]
fn test_get_name() {
let name = Some("Foo".to_string());
let attrs = vec![];
let node = test_node(name, attrs);
let node = make_node(name, attrs);
assert_eq!(node.name(), Some("Foo"));
}

#[test]
fn test_get_name_with_rename() {
let name = Some("Foo".to_string());
let attrs = vec![r#"#[serde(rename = "Bar")]"#.to_string()];
let node = test_node(name, attrs);
let node = make_node(name, attrs);
assert_eq!(node.name(), Some("Bar"));
}

#[test]
fn test_get_name_with_rename_no_whitespace() {
let name = Some("Foo".to_string());
let attrs = vec![r#"#[serde(rename="Bar")]"#.to_string()];
let node = test_node(name, attrs);
let node = make_node(name, attrs);
assert_eq!(node.name(), Some("Bar"));
}

#[test]
fn test_get_name_with_no_name() {
let name = None;
let attrs = vec![];
let node = test_node(name, attrs);
let node = make_node(name, attrs);
assert_eq!(node.name(), None);
}
}
15 changes: 4 additions & 11 deletions crux_cli/src/codegen/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ use crate::codegen::Registry;
fn cat_facts_json() {
static RUSTDOC: &'static [u8] = include_bytes!("fixtures/cat_facts/rustdoc.json");
let crate_: Crate = serde_json::from_slice(RUSTDOC).unwrap();
let nodes = super::parse(crate_);

let actual = super::run(nodes);
let actual = super::run(crate_);

let writer = File::create("fixtures-cat_facts-actual.json").unwrap();
serde_json::to_writer_pretty(writer, &actual).unwrap();
Expand All @@ -25,9 +23,7 @@ fn cat_facts_json() {
fn notes_json() {
static RUSTDOC: &'static [u8] = include_bytes!("fixtures/notes/rustdoc.json");
let crate_: Crate = serde_json::from_slice(RUSTDOC).unwrap();
let nodes = super::parse(crate_);

let actual = super::run(nodes);
let actual = super::run(crate_);

let writer = File::create("fixtures-notes-actual.json").unwrap();
serde_json::to_writer_pretty(writer, &actual).unwrap();
Expand All @@ -40,9 +36,7 @@ fn notes_json() {
fn bridge_echo() {
static RUSTDOC: &'static [u8] = include_bytes!("fixtures/bridge_echo_rustdoc.json");
let crate_: Crate = serde_json::from_slice(RUSTDOC).unwrap();
let nodes = super::parse(crate_);

let containers = super::run(nodes);
let containers = super::run(crate_);

insta::assert_debug_snapshot!(&containers, @r#"
{
Expand Down Expand Up @@ -86,9 +80,8 @@ fn bridge_echo() {
fn cat_facts() {
static RUSTDOC: &'static [u8] = include_bytes!("fixtures/cat_facts/rustdoc.json");
let crate_: Crate = serde_json::from_slice(RUSTDOC).unwrap();
let nodes = super::parse(crate_);

let registry = super::run(nodes);
let registry = super::run(crate_);

insta::assert_debug_snapshot!(&registry, @r#"
{
Expand Down

0 comments on commit 7ee1e77

Please sign in to comment.