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: mod.rs
    path of file: ./repos/heimdall-rs/crates/core/src/cfg
    
    the code of the file until where you have to start completion: pub mod graph;
pub mod output;
use derive_builder::Builder;
use ethers::types::H160;
use heimdall_common::{
    ether::{
        bytecode::get_bytecode_from_target,
        compiler::{detect_compiler, Compiler},
        selectors::find_function_selectors,
    },
    info_spinner,
    utils::{
        strings::{encode_hex, StringExt},
        threading::run_wit
    
pub async fn cfg(args: CFGArgs) -> Result<CFGResult, Error> {
    use std::time::Instant;
    let now = Instant::now();

    let mut trace = TraceFactory::default();

    // add the call to the trace
    let cfg_call = trace.add_call(
        0,
        line!(),
        "heimdall".to_string(),
        "cfg".to_string(),
        vec![args.target.truncate(64)],
        "()".to_string(),
    );

    let contract_bytecode = get_bytecode_from_target(&args.target, &args.rpc_url)
        .await
        .map_err(|e| Error::Generic(format!("failed to get bytecode from target: {}", e)))?;

    // disassemble the bytecode
    let disassembled_bytecode = disassemble(DisassemblerArgs {
        target: encode_hex(contract_bytecode.clone()),
        rpc_url: args.rpc_url.clone(),
        decimal_counter: false,
        name: String::from(""),
        output: String::from(""),
    })
    .await?;

    // add the call to the trace
    trace.add_call(
        cfg_call,
        line!(),
        "heimdall".to_string(),
        "disassemble".to_string(),
        vec![format!("{} bytes", contract_bytecode.len())],
        "()".to_string(),
    );

    // perform versioning and compiler heuristics
    let (compiler, version) = detect_compiler(&contract_bytecode);
    trace.add_call(
        cfg_call,
        line!(),
        "heimdall".to_string(),
        "detect_compiler".to_string(),
        vec![format!("{} bytes", contract_bytecode.len())],
        format!("({compiler}, {version})"),
    );

    if compiler == Compiler::Solc {
        debug!("detected compiler {} {}", compiler, version);
    } else {
        warn!("detected compiler {} {} is not supported by heimdall", compiler, version);
    }

    // create a new EVM instance
    let evm = VM::new(
        &contract_bytecode,
        &[],
        H160::default(),
        H160::default(),
        H160::default(),
        0,
        u128::max_value(),
    );

    // add the creation to the trace
    let vm_trace = trace.add_creation(
        cfg_call,
        line!(),
        "contract".to_string(),
        encode_hex(contract_bytecode.clone()).truncate(64),
        contract_bytecode
            .len()
            .try_into()
            .map_err(|_| Error::ParseError("failed to parse bytecode length".to_string()))?,
    );

    // find all selectors in the bytecode
    let selectors = find_function_selectors(&evm, &disassembled_bytecode);
    info!("found {} possible function selectors.", selectors.len());
    info!("performing symbolic execution on '{}' .", args.target.truncate(64));

    // create a new progress bar
    let progress = ProgressBar::new_spinner();
    progress.enable_steady_tick(Duration::from_millis(100));
    progress.set_style(info_spinner!());

    // create a new petgraph StableGraph
    let mut contract_cfg = Graph::<String, String>::new();

    // add the call to the trace
    let map_trace = trace.add_call(
        vm_trace,
        line!(),
        "heimdall".to_string(),
        "cfg".to_string(),
        vec![format!("{} bytes", contract_bytecode.len() / 2usize)],
        "()".to_string(),
    );

    // get a map of possible jump destinations
    let (map, jumpdest_count) =
        match run_with_timeout(move || evm.symbolic_exec(), Duration::from_millis(args.timeout)) {
            Some(map) => map.map_err(|e| {
                Error::Generic(format!("failed to perform symbolic execution: {}", e))
            })?,
            None => {
                return Err(Error::Generic("symbolic execution timed out".to_string()));
            }
        };

    // add jumpdests to the trace
    trace.add_info(
        map_trace,
        line!(),
        &format!("traced and executed {jumpdest_count} possible paths."),
    );

    trace!("building control flow graph from symbolic execution trace");
    build_cfg(&map, &mut contract_cfg, None, false)?;

    progress.finish_and_clear();
    info!("symbolic execution completed.");
    debug!("control flow graph generated in {:?}.", now.elapsed());
    trace.display();

    Ok(CFGResult { graph: contract_cfg, _trace: trace })
}