<- MyBlog
11th August, 2022
5 min read
Debugging proc macros using croc-look
The terminal solution right now for debugging procedural macros in rust is called cargo-expand which is a good solution but what if,
- You want a declutered, straight to the point view of what your code is generating
 - You want to see the output of your macro as your writing it (live reloading)
 
              The reason why I think croc-look is a good solution
              is that it allows you to think straight in terms of the code your
              generating.
              
              croc-look will help the community better debug proc
              macros and make them tiny bit easier to make. 
              Getting started is as easy as
            
cargo install croc-look
            Let's take a look at this
#[derive(Serialize, Debug, Clone)]
struct T {}
            
              Suppose your the person who's writing the derive macro
              Serialize. Your implementing the
              Serialize
              trait for a struct. Now you want to see the whole impl.
              
            
➜ croc-look -t Serialize -i T
            Is enough to find the impl since there's only one impl in the scope right now. Let's look at edge cases
#[derive(Serialize, Debug, Clone)]
struct T {}
#[derive(Serialize, Debug, Clone)]
struct B {}
mod module {
    use super::*;
    #[derive(Serialize, Debug, Clone)]
    struct C(usize);
    #[derive(Serialize, Debug, Clone)]
    struct D(u64);
}
            The challenge is to look at Serialize impl for each struct we see in the code above. Let's look in the module first
➜ croc-look -p module --trait-impl Serialize -i C
            
              This shows you the impl of Serialize in the module
              module for struct C. Works the same with
              nested modules
            
mod module {
    use super::*;
    #[derive(Serialize, Debug, Clone)]
    struct C(usize);
    #[derive(Serialize, Debug, Clone)]
    struct D(u64);
    mod inner_module {
        use super::*;
        #[derive(Serialize, Debug, Clone)]
        struct E(u64);
    }
}
            
              The command
              croc-look -p module::inner_module --trait-impl Serialize -i
                E
              outputs
            
impl _serde::Serialize for E {
    fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error>
    where
        __S: _serde::Serializer,
    {
        _serde::Serializer::serialize_newtype_struct(__serializer, "E", &self.0)
    }
}
            
              This will work without
              -p module::inner_module assuming the struct names
              aren't the same across modules but it'll be faster to execute if
              you specify the module since croc-look will only
              parse that module.
            
The --watch flag
            The watch feature is gonna come in handy when your working on big macros. It features a TUI which allows you to see your code live
              The left side shows the --watch flag of
              croc-look, right part shows me working on a
              proc-macro = true crate
            
              Once you're able to form the command which shows you the macro you
              want, you are able to use the --watch flag to watch a
              particular directory recursively or even a single file.
              
              Hope this makes proc macros a little bit easier for you!
            
Links: