You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: recipe_graphviz.rs
    path of file: ./repos/veloren/common/src/bin
    
    the code of the file until where you have to start completion: use hashbrown::HashMap;
use petgraph::{
    dot::{Config, Dot},
    Graph,
};
use std::{fs::File, io::Write};
use veloren_common::{
    assets::AssetExt,
    comp::item::ItemDesc,
    recipe::{RecipeBook, RecipeInput},
};

fn main() {
    let recipes = RecipeBook::load_expect_cloned("common.recipe_book");
    let mut graph = Graph::new();
    let mut nodes = HashMap::new();
    let mut add_node = |graph: &mut Graph<_, _>, node: &str| {
        *nodes
            .entry(node.to_owned())
            .or_insert_with(|| graph.add_node(node.to_owned()))
    };
    for (_, recipe) in recipes.iter() {
        let output = String::from(
            recipe
                .output
                .0
                .item_definition_id()
                .itemdef_id()
                .expect("Recipe book can only create simple
    
fn main() {
    let recipes = RecipeBook::load_expect_cloned("common.recipe_book");
    let mut graph = Graph::new();
    let mut nodes = HashMap::new();
    let mut add_node = |graph: &mut Graph<_, _>, node: &str| {
        *nodes
            .entry(node.to_owned())
            .or_insert_with(|| graph.add_node(node.to_owned()))
    };
    for (_, recipe) in recipes.iter() {
        let output = String::from(
            recipe
                .output
                .0
                .item_definition_id()
                .itemdef_id()
                .expect("Recipe book can only create simple items (probably)"),
        );
        let inputs = recipe
            .inputs
            .iter()
            .map(|(i, _, _)| i)
            .filter_map(|input| {
                if let RecipeInput::Item(item) = input {
                    item.item_definition_id().itemdef_id().map(String::from)
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();
        let out_node = add_node(&mut graph, &output);
        for input in inputs.iter() {
            let in_node = add_node(&mut graph, input);
            graph.add_edge(in_node, out_node, ());
        }
    }
    // you can render the dot file as a png with `dot -Tpng recipe_graph.dot >
    // recipe_graph.png` or interactively view it with `xdot recipe_graph.dot`
    let mut f = File::create("recipe_graph.dot").unwrap();
    writeln!(f, "digraph {{").unwrap();
    writeln!(f, "rankdir = \"LR\"").unwrap();
    writeln!(
        f,
        "{:#?}",
        Dot::with_attr_getters(
            &graph,
            &[Config::EdgeNoLabel, Config::GraphContentOnly],
            &|_, _| "".to_owned(),
            &|_, _| { "constraint=false".to_owned() }
        )
    )
    .unwrap();
    writeln!(f, "}}").unwrap();
}