# Cairo Annotations

The `cairo-annotations` crate provides tools tailored for working with annotations in the Cairo language. These
annotations are part of the Sierra Debug Information format and serve to enrich the code by detailing information.

To see JSON example of the annotations, check the following [file](./examples/annotation.json).

## Features of Cairo Annotations

### Structured Annotations

`cairo-annotations` offers a structured representation, allowing for more ergonomic manipulation of annotations. Some
key features include:

- [**Coverage Annotations**](#coverage-annotations): Track locations in the Cairo code that correspond to specific Sierra statements.
- [**Profiler Annotations**](#profiler-annotations): Provide mappings from Sierra statements to fully qualified Cairo paths, detailing which
  functions in the Cairo code triggered them.
- [**Debugger Annotations**](#debugger-annotations): Provide debug information per sierra function, including its location and information about its variables.
- [**Type Names Annotations**](#type-names-annotations): Provide names and member/variant information for Sierra struct and enum types.
  

All annotations implement the `TryFromDebugInfo` trait, enabling their extraction from Sierra debug information. Here's
a simple example:

```rust
let annotations = VersionedCoverageAnnotations::try_from_debug_info(sierra_debug_info).unwrap();
```

### Coverage Annotations

Coverage annotations provide a mapping from Sierra statement indices to sources in the Cairo code that resulted in their
creation. For extensive documentation,
see [CoverageAnnotationsV1](./crates/cairo-annotations/src/annotations/coverage.rs).

Example to retrieve code location information:

```rust
use cairo_annotations::annotations::coverage::{
    CodeLocation, ColumnNumber, CoverageAnnotationsV1, LineNumber, SourceCodeLocation,
    SourceCodeSpan, SourceFileFullPath, VersionedCoverageAnnotations,
};
use cairo_annotations::annotations::TryFromDebugInfo;
use cairo_lang_sierra::program::StatementIdx;

let VersionedCoverageAnnotations::V1(annotations) =
    VersionedCoverageAnnotations::try_from_debug_info(sierra_debug_info).unwrap();

let code_locations = annotations
    .statements_code_locations
    .get(&StatementIdx(331))
    .unwrap();

assert_eq!(
    code_locations,
    &[CodeLocation(
        SourceFileFullPath("/path/to/my/file.cairo".into()),
        SourceCodeSpan {
            start: SourceCodeLocation { line: LineNumber(7), col: ColumnNumber(4) },
            end: SourceCodeLocation { line: LineNumber(7), col: ColumnNumber(4) },
        },
        None
    )]
);
```

### Profiler Annotations

Profiler annotations map Sierra statement indices to Cairo function paths, showing which functions led to their
generation. Detailed information is available
in [ProfilerAnnotationsV1](./crates/cairo-annotations/src/annotations/profiler.rs).

Example to get the Cairo path:

```rust
use cairo_annotations::annotations::profiler::{
    FunctionName, ProfilerAnnotationsV1, VersionedProfilerAnnotations,
};
use cairo_annotations::annotations::TryFromDebugInfo;
use cairo_lang_sierra::program::StatementIdx;

let VersionedProfilerAnnotations::V1(annotations) =
    VersionedProfilerAnnotations::try_from_debug_info(sierra_debug_info).unwrap();

let functions_names = annotations
    .statements_functions
    .get(&StatementIdx(331))
    .unwrap();

assert_eq!(
    functions_names,
    &[FunctionName("scarb_template::fib".into())]
);
```

### Debugger Annotations

Debugger annotations map Sierra functions ids to its debug information, allowing to explore the location of the Cairo 
function the Sierra function was compiled from and mappings between Cairo and Sierra variables.

Detailed information is available in [DebuggerAnnotationsV1](./crates/cairo-annotations/src/annotations/debugger.rs).

Example to get the function debug info:

```rust
use cairo_annotations::annotations::coverage::SourceFileFullPath;
use cairo_annotations::annotations::debugger::{
    DebuggerAnnotationsV1, VersionedDebuggerAnnotations, SierraFunctionId
};
use cairo_annotations::annotations::TryFromDebugInfo;

let VersionedDebuggerAnnotations::V1(annotations) =
    VersionedDebuggerAnnotations::try_from_debug_info(sierra_debug_info).unwrap();

let function_debug_info = annotations
    .functions_info
    .get(&SierraFunctionId(727041))
    .unwrap();

assert_eq!(
    function_debug_info.function_file_path,
    SourceFileFullPath("scarb_template/src/lib.cairo".to_string())
);
```

### Type Names Annotations

Type names annotations map Sierra type IDs to their debug information (concretized name and member/variant names) for
struct and enum types.

Detailed information is available in [TypeNamesAnnotationsV1](./crates/cairo-annotations/src/annotations/type_names.rs).

Example to get the struct info:

```rust
use cairo_annotations::annotations::type_names::{
    SierraTypeId, TypeNamesAnnotationsV1, VersionedTypeNamesAnnotations,
};
use cairo_annotations::annotations::TryFromDebugInfo;

let VersionedTypeNamesAnnotations::V1(annotations) =
    VersionedTypeNamesAnnotations::try_from_debug_info(sierra_debug_info).unwrap();

let struct_info = annotations
    .structs
    .get(&SierraTypeId(42))
    .unwrap();

assert_eq!(struct_info.name, "my_package::MyStruct");
assert_eq!(struct_info.members, vec!["field_a".to_string(), "field_b".to_string()]);
```

### Versioning

Annotations are versioned to ensure backward compatibility with different formats. The `VersionedCoverageAnnotations`,
`VersionedProfilerAnnotations`, `VersionedDebuggerAnnotations` and `VersionedTypeNamesAnnotations` enums encapsulate
the different versions of the annotations. The versioning goes as `V1`, `V2`, `V3`, and so on, with the greatest version
representing the latest version.

## Integration with snforge

Annotations are particularly useful for getting information about executed code. If you are using `snforge`, you can
leverage the `--save-trace-data` flag to generate trace data.

Deserialize this data using `VersionedCallTrace` from the `cairo-annotations` crate, and subsequently
use `map_pcs_to_sierra_statement_ids` to map the trace to Sierra statement IDs.
