Skip to content

Commit

Permalink
respect serde rename
Browse files Browse the repository at this point in the history
  • Loading branch information
StuartHarris committed Nov 21, 2024
1 parent 5643a91 commit c548406
Show file tree
Hide file tree
Showing 9 changed files with 1,799 additions and 144 deletions.
36 changes: 36 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crux_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ clap = { version = "4.4.18", features = ["derive"] }
console = "0.15.8"
guppy = "0.17.4"
ignore = "0.4.23"
lazy-regex = "3.3.0"
libc = "0.2.161"
petgraph = "0.6.5"
ramhorns = "1.0.1"
Expand Down
18 changes: 13 additions & 5 deletions crux_cli/codegen.fish
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
#!/usr/bin/env fish
argparse 'h/help' -- $argv
or return

if set -q _flag_help
echo must specify example as the single argument
return 0
end

argparse --min-args=1 -- $argv
or return

cargo build

for d in ../examples/simple_counter
pushd $d
../../target/debug/crux codegen --lib shared
popd
end
pushd $argv[1]
../../target/debug/crux codegen --lib shared
popd
2 changes: 2 additions & 0 deletions crux_cli/src/codegen/format.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(dead_code)]

use std::{
cell::{Ref, RefCell, RefMut},
collections::BTreeMap,
Expand Down
214 changes: 214 additions & 0 deletions crux_cli/src/codegen/generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
use std::collections::HashMap;

use rustdoc_types::{Type, Variant};

use crate::codegen::format::{ContainerFormat, Named};

use super::{
format::{Format, VariantFormat},
parser::Node,
};

pub(crate) fn generate(edges: &[(Node, Node)]) {
let mut containers = HashMap::new();
let mut variant_index = 0;
for (from, to) in edges {
let Some(name) = get_name(&from) else {
continue;
};
let Some(item) = &from.item else {
continue;
};
let mut container = None;
match &item.inner {
rustdoc_types::ItemEnum::Struct(s) => match &s.kind {
rustdoc_types::StructKind::Unit => {}
rustdoc_types::StructKind::Tuple(_vec) => {}
rustdoc_types::StructKind::Plain {
fields: _,
has_stripped_fields: _,
} => {
let val = ContainerFormat::Struct(vec![]);
container = Some(containers.entry(name).or_insert(val));
}
},
rustdoc_types::ItemEnum::Enum(_e) => {
if containers.contains_key(name) {
variant_index += 1;
} else {
variant_index = 0;
}
container = Some(
containers
.entry(name)
.or_insert(ContainerFormat::Enum(Default::default())),
);
}
_ => continue,
}

let Some(name) = get_name(&to) else {
continue;
};
let Some(item) = &to.item else {
continue;
};
match &item.inner {
rustdoc_types::ItemEnum::StructField(t) => {
let Some(ContainerFormat::Struct(ref mut v)) = &mut container else {
continue;
};
v.push(Named {
name: name.to_string(),
value: t.into(),
});
}
rustdoc_types::ItemEnum::Variant(t) => {
let Some(ContainerFormat::Enum(ref mut v)) = &mut container else {
continue;
};
v.insert(
variant_index,
Named {
name: name.to_string(),
value: t.into(),
},
);
}
_ => continue,
}
println!("{:?} \n-> {:?}\n", item, to);
}
println!();
println!("{:#?}", containers);
}

impl From<&Type> for Format {
fn from(value: &Type) -> Self {
match value {
Type::ResolvedPath(path) => Format::TypeName(path.name.clone()),
Type::DynTrait(_dyn_trait) => todo!(),
Type::Generic(_) => todo!(),
Type::Primitive(s) => match s.as_ref() {
"u32" => Format::U32,
_ => todo!(),
},
Type::FunctionPointer(_function_pointer) => todo!(),
Type::Tuple(_vec) => todo!(),
Type::Slice(_) => todo!(),
Type::Array { type_: _, len: _ } => todo!(),
Type::Pat {
type_: _,
__pat_unstable_do_not_use,
} => todo!(),
Type::ImplTrait(_vec) => todo!(),
Type::Infer => todo!(),
Type::RawPointer {
is_mutable: _,
type_: _,
} => todo!(),
Type::BorrowedRef {
lifetime: _,
is_mutable: _,
type_: _,
} => todo!(),
Type::QualifiedPath {
name: _,
args: _,
self_type: _,
trait_: _,
} => todo!(),
}
}
}

impl From<&Variant> for VariantFormat {
fn from(value: &Variant) -> Self {
match &value.kind {
rustdoc_types::VariantKind::Plain => VariantFormat::Unit,
rustdoc_types::VariantKind::Tuple(_vec) => VariantFormat::Tuple(vec![]),
rustdoc_types::VariantKind::Struct {
fields: _,
has_stripped_fields: _,
} => todo!(),
}
}
}

fn get_name(node: &Node) -> Option<&str> {
node.item.as_ref().and_then(|item| {
let mut new_name = "";
for attr in &item.attrs {
if let Some((_, n)) =
lazy_regex::regex_captures!(r#"\[serde\(rename = "(\w+)"\)\]"#, attr)
{
new_name = n;
}
}
if new_name.is_empty() {
item.name.as_deref()
} else {
Some(new_name)
}
})
}

#[cfg(test)]
mod test {
use rustdoc_types::{Generics, Id, Item, ItemEnum, Struct, StructKind, Visibility};

use super::*;

fn test_node(name: Option<String>, attrs: Vec<String>) -> Node {
Node {
item: Some(Item {
name,
attrs,
inner: ItemEnum::Struct(Struct {
kind: StructKind::Plain {
fields: vec![],
has_stripped_fields: false,
},
generics: Generics {
params: vec![],
where_predicates: vec![],
},
impls: vec![],
}),
id: Id(0),
crate_id: 0,
span: None,
visibility: Visibility::Public,
docs: None,
links: Default::default(),
deprecation: None,
}),
id: Id(0),
path: None,
}
}

#[test]
fn test_get_name() {
let name = Some("Foo".to_string());
let attrs = vec![];
let node = test_node(name, attrs);
assert_eq!(get_name(&node), 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);
assert_eq!(get_name(&node), Some("Bar"));
}

#[test]
fn test_get_name_with_no_name() {
let name = None;
let attrs = vec![];
let node = test_node(name, attrs);
assert_eq!(get_name(&node), None);
}
}
4 changes: 2 additions & 2 deletions crux_cli/src/codegen/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod format;
mod generator;
mod parser;
mod rust;

use std::fs::File;

Expand Down Expand Up @@ -42,7 +42,7 @@ pub async fn codegen(args: &CodegenArgs) -> Result<()> {

let edges = parser::parse(&crate_)?;

rust::generate(&edges);
generator::generate(&edges);

Ok(())
}
19 changes: 10 additions & 9 deletions crux_cli/src/codegen/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,15 +259,16 @@ pub fn parse(crate_: &Crate) -> Result<Vec<(Node, Node)>> {

prog.run();

// std::fs::write("/tmp/edge.json", serde_json::to_string(&prog.edge).unwrap())?;
// std::fs::write(
// "/tmp/field.json",
// serde_json::to_string(&prog.field).unwrap(),
// )?;
// std::fs::write(
// "/tmp/variant.json",
// serde_json::to_string(&prog.variant).unwrap(),
// )?;
// write field and variant edges to disk for debugging
std::fs::write("/tmp/edge.json", serde_json::to_string(&prog.edge).unwrap())?;
std::fs::write(
"/tmp/field.json",
serde_json::to_string(&prog.field).unwrap(),
)?;
std::fs::write(
"/tmp/variant.json",
serde_json::to_string(&prog.variant).unwrap(),
)?;

let mut all_edges = Vec::new();
all_edges.extend(prog.field);
Expand Down
Loading

0 comments on commit c548406

Please sign in to comment.