Skip to content

Commit 865e00c

Browse files
authored
Feature/log id expose (#1699)
Example of usage: https://github.com/FuelLabs/fuel-rust-indexer/blob/main/crates/indexer/processors/receipt_parser.rs#L17 <!-- List the issues this PR closes (if any) in a bullet list format, e.g.: - Closes #ABCD - Closes #EFGH --> # Release notes <!-- Use this only if this PR requires a mention in the Release Notes Summary. Valuable features and critical fixes are good examples. For everything else, please delete the whole section. --> In this release, we: - Did this and that <!-- edit this text only --> # Summary <!-- Please write a summary of your changes and why you made them. Not all PRs will be complex or substantial enough to require this section, so you can remove it if you think it's unnecessary. --> # Breaking Changes <!-- If the PR has breaking changes, please detail them in this section and remove this comment. Remove this section if there are no breaking changes. --> # Checklist - [ ] All **changes** are **covered** by **tests** (or not applicable) - [ ] All **changes** are **documented** (or not applicable) - [ ] I **reviewed** the **entire PR** myself (preferably, on GH UI) - [ ] I **described** all **Breaking Changes** (or there's none)
1 parent f2afc5f commit 865e00c

File tree

5 files changed

+132
-28
lines changed

5 files changed

+132
-28
lines changed

packages/fuels-code-gen/src/program_bindings/abigen.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{collections::HashSet, path::PathBuf};
22

33
pub use abigen_target::{Abi, AbigenTarget, ProgramType};
4-
use fuel_abi_types::abi::full_program::FullTypeDeclaration;
4+
use fuel_abi_types::abi::full_program::{FullLoggedType, FullTypeDeclaration};
55
use inflector::Inflector;
66
use itertools::Itertools;
77
use proc_macro2::TokenStream;
@@ -69,8 +69,13 @@ impl Abigen {
6969
let custom_types = Self::filter_custom_types(&parsed_targets);
7070
let shared_types = Self::filter_shared_types(custom_types);
7171

72+
let logged_types = parsed_targets
73+
.iter()
74+
.flat_map(|abi| abi.source.abi.logged_types.clone())
75+
.collect_vec();
7276
let bindings = Self::generate_all_bindings(parsed_targets, no_std, &shared_types)?;
73-
let shared_types = Self::generate_shared_types(shared_types, no_std)?;
77+
78+
let shared_types = Self::generate_shared_types(shared_types, &logged_types, no_std)?;
7479

7580
let mod_name = ident("abigen_bindings");
7681
Ok(shared_types.merge(bindings).wrap_in_mod(mod_name))
@@ -98,7 +103,12 @@ impl Abigen {
98103

99104
let recompile_trigger =
100105
Self::generate_macro_recompile_trigger(target.source.path.as_ref(), no_std);
101-
let types = generate_types(&target.source.abi.types, shared_types, no_std)?;
106+
let types = generate_types(
107+
&target.source.abi.types,
108+
shared_types,
109+
&target.source.abi.logged_types,
110+
no_std,
111+
)?;
102112
let bindings = generate_bindings(target, no_std)?;
103113
Ok(recompile_trigger
104114
.merge(types)
@@ -124,9 +134,10 @@ impl Abigen {
124134

125135
fn generate_shared_types(
126136
shared_types: HashSet<FullTypeDeclaration>,
137+
logged_types: &Vec<FullLoggedType>,
127138
no_std: bool,
128139
) -> Result<GeneratedCode> {
129-
let types = generate_types(&shared_types, &HashSet::default(), no_std)?;
140+
let types = generate_types(&shared_types, &HashSet::default(), logged_types, no_std)?;
130141

131142
if types.is_empty() {
132143
Ok(Default::default())

packages/fuels-code-gen/src/program_bindings/custom_types.rs

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::collections::HashSet;
1+
use std::collections::{HashMap, HashSet};
22

3-
use fuel_abi_types::abi::full_program::FullTypeDeclaration;
3+
use fuel_abi_types::abi::full_program::{FullLoggedType, FullTypeDeclaration};
44
use itertools::Itertools;
55
use quote::quote;
66

@@ -16,7 +16,7 @@ use crate::{
1616

1717
mod enums;
1818
mod structs;
19-
mod utils;
19+
pub(crate) mod utils;
2020

2121
/// Generates Rust code for each type inside `types` if:
2222
/// * the type is not present inside `shared_types`, and
@@ -29,21 +29,28 @@ mod utils;
2929
/// * `types`: Types you wish to generate Rust code for.
3030
/// * `shared_types`: Types that are shared between multiple
3131
/// contracts/scripts/predicates and thus generated elsewhere.
32-
pub(crate) fn generate_types<'a, T: IntoIterator<Item = &'a FullTypeDeclaration>>(
33-
types: T,
32+
pub(crate) fn generate_types<'a>(
33+
types: impl IntoIterator<Item = &'a FullTypeDeclaration>,
3434
shared_types: &HashSet<FullTypeDeclaration>,
35+
logged_types: impl IntoIterator<Item = &'a FullLoggedType>,
3536
no_std: bool,
3637
) -> Result<GeneratedCode> {
38+
let log_ids: HashMap<_, _> = logged_types
39+
.into_iter()
40+
.map(|l| (l.application.type_decl.type_field.clone(), l.log_id.clone()))
41+
.collect();
42+
3743
types
3844
.into_iter()
3945
.filter(|ttype| !should_skip_codegen(ttype))
4046
.map(|ttype: &FullTypeDeclaration| {
47+
let log_id = log_ids.get(&ttype.type_field);
4148
if shared_types.contains(ttype) {
4249
reexport_the_shared_type(ttype, no_std)
4350
} else if ttype.is_struct_type() {
44-
expand_custom_struct(ttype, no_std)
51+
expand_custom_struct(ttype, no_std, log_id)
4552
} else {
46-
expand_custom_enum(ttype, no_std)
53+
expand_custom_enum(ttype, no_std, log_id)
4754
}
4855
})
4956
.fold_ok(GeneratedCode::default(), |acc, generated_code| {
@@ -84,7 +91,7 @@ fn reexport_the_shared_type(ttype: &FullTypeDeclaration, no_std: bool) -> Result
8491
// Others like 'std::vec::RawVec' are skipped because they are
8592
// implementation details of the contract's Vec type and are not directly
8693
// used in the SDK.
87-
fn should_skip_codegen(type_decl: &FullTypeDeclaration) -> bool {
94+
pub fn should_skip_codegen(type_decl: &FullTypeDeclaration) -> bool {
8895
if !type_decl.is_custom_type() {
8996
return true;
9097
}
@@ -165,7 +172,11 @@ mod tests {
165172
.into_iter()
166173
.collect::<HashMap<_, _>>();
167174

168-
let actual = expand_custom_enum(&FullTypeDeclaration::from_counterpart(&p, &types), false)?;
175+
let actual = expand_custom_enum(
176+
&FullTypeDeclaration::from_counterpart(&p, &types),
177+
false,
178+
None,
179+
)?;
169180

170181
let expected = quote! {
171182
#[allow(clippy::enum_variant_names)]
@@ -198,8 +209,12 @@ mod tests {
198209
};
199210
let types = [(0, p.clone())].into_iter().collect::<HashMap<_, _>>();
200211

201-
expand_custom_enum(&FullTypeDeclaration::from_counterpart(&p, &types), false)
202-
.expect_err("Was able to construct an enum without variants");
212+
expand_custom_enum(
213+
&FullTypeDeclaration::from_counterpart(&p, &types),
214+
false,
215+
None,
216+
)
217+
.expect_err("Was able to construct an enum without variants");
203218

204219
Ok(())
205220
}
@@ -249,7 +264,11 @@ mod tests {
249264
.into_iter()
250265
.collect::<HashMap<_, _>>();
251266

252-
let actual = expand_custom_enum(&FullTypeDeclaration::from_counterpart(&p, &types), false)?;
267+
let actual = expand_custom_enum(
268+
&FullTypeDeclaration::from_counterpart(&p, &types),
269+
false,
270+
None,
271+
)?;
253272

254273
let expected = quote! {
255274
#[allow(clippy::enum_variant_names)]
@@ -311,7 +330,11 @@ mod tests {
311330
.into_iter()
312331
.collect::<HashMap<_, _>>();
313332

314-
let actual = expand_custom_enum(&FullTypeDeclaration::from_counterpart(&p, &types), false)?;
333+
let actual = expand_custom_enum(
334+
&FullTypeDeclaration::from_counterpart(&p, &types),
335+
false,
336+
None,
337+
)?;
315338

316339
let expected = quote! {
317340
#[allow(clippy::enum_variant_names)]
@@ -385,7 +408,12 @@ mod tests {
385408
.into_iter()
386409
.collect::<HashMap<_, _>>();
387410

388-
let actual = expand_custom_enum(&FullTypeDeclaration::from_counterpart(&p, &types), false)?;
411+
let log_id = "42".to_string();
412+
let actual = expand_custom_enum(
413+
&FullTypeDeclaration::from_counterpart(&p, &types),
414+
false,
415+
Some(&log_id),
416+
)?;
389417

390418
let expected = quote! {
391419
#[allow(clippy::enum_variant_names)]
@@ -401,6 +429,11 @@ mod tests {
401429
pub enum EnumLevel3 {
402430
El2(self::EnumLevel2),
403431
}
432+
433+
impl ::fuels::core::codec::Log for EnumLevel3 {
434+
const LOG_ID: &'static str = "42";
435+
const LOG_ID_U64: u64 = 42u64;
436+
}
404437
};
405438

406439
assert_eq!(actual.code().to_string(), expected.to_string());
@@ -460,8 +493,11 @@ mod tests {
460493
.into_iter()
461494
.collect::<HashMap<_, _>>();
462495

463-
let actual =
464-
expand_custom_struct(&FullTypeDeclaration::from_counterpart(&p, &types), false)?;
496+
let actual = expand_custom_struct(
497+
&FullTypeDeclaration::from_counterpart(&p, &types),
498+
false,
499+
None,
500+
)?;
465501

466502
let expected = quote! {
467503
#[derive(
@@ -508,8 +544,11 @@ mod tests {
508544
};
509545
let types = [(0, p.clone())].into_iter().collect::<HashMap<_, _>>();
510546

511-
let actual =
512-
expand_custom_struct(&FullTypeDeclaration::from_counterpart(&p, &types), false)?;
547+
let actual = expand_custom_struct(
548+
&FullTypeDeclaration::from_counterpart(&p, &types),
549+
false,
550+
None,
551+
)?;
513552

514553
let expected = quote! {
515554
#[derive(
@@ -577,8 +616,12 @@ mod tests {
577616
.into_iter()
578617
.collect::<HashMap<_, _>>();
579618

580-
let actual =
581-
expand_custom_struct(&FullTypeDeclaration::from_counterpart(&p, &types), false)?;
619+
let log_id = "13".to_string();
620+
let actual = expand_custom_struct(
621+
&FullTypeDeclaration::from_counterpart(&p, &types),
622+
false,
623+
Some(&log_id),
624+
)?;
582625

583626
let expected = quote! {
584627
#[derive(
@@ -602,6 +645,11 @@ mod tests {
602645
}
603646
}
604647
}
648+
649+
impl ::fuels::core::codec::Log for Cocktail {
650+
const LOG_ID: &'static str = "13";
651+
const LOG_ID_U64: u64 = 13u64;
652+
}
605653
};
606654

607655
assert_eq!(actual.code().to_string(), expected.to_string());
@@ -620,7 +668,7 @@ mod tests {
620668
let shared_types = HashSet::from([type_decl.clone()]);
621669

622670
// when
623-
let generated_code = generate_types(&[type_decl], &shared_types, false).unwrap();
671+
let generated_code = generate_types(&[type_decl], &shared_types, [], false).unwrap();
624672

625673
// then
626674
let expected_code = quote! {

packages/fuels-code-gen/src/program_bindings/custom_types/enums.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{
2020
pub(crate) fn expand_custom_enum(
2121
type_decl: &FullTypeDeclaration,
2222
no_std: bool,
23+
log_id: Option<&String>,
2324
) -> Result<GeneratedCode> {
2425
let enum_type_path = type_decl.custom_type_path()?;
2526
let enum_ident = enum_type_path.ident().unwrap();
@@ -30,7 +31,7 @@ pub(crate) fn expand_custom_enum(
3031
}
3132
let generics = extract_generic_parameters(type_decl);
3233

33-
let code = enum_decl(enum_ident, &components, &generics, no_std);
34+
let code = enum_decl(enum_ident, &components, &generics, no_std, log_id);
3435

3536
let enum_code = GeneratedCode::new(code, HashSet::from([enum_ident.into()]), no_std);
3637

@@ -70,14 +71,28 @@ fn enum_decl(
7071
components: &Components,
7172
generics: &[Ident],
7273
no_std: bool,
74+
log_id: Option<&String>,
7375
) -> TokenStream {
7476
let maybe_disable_std = no_std.then(|| quote! {#[NoStd]});
7577

7678
let enum_variants = components.as_enum_variants();
7779
let unused_generics_variant = components.generate_variant_for_unused_generics(generics);
78-
let (_, generics_w_bounds) = tokenize_generics(generics);
80+
let (generics_wo_bounds, generics_w_bounds) = tokenize_generics(generics);
7981
let maybe_impl_error = maybe_impl_error(enum_ident, components);
8082

83+
let log_impl = log_id.map(|log_id| {
84+
let log_id_u64: u64 = log_id
85+
.parse::<u64>()
86+
.expect("log id should be a valid u64 string");
87+
88+
quote! {
89+
impl #generics_w_bounds ::fuels::core::codec::Log for #enum_ident #generics_wo_bounds {
90+
const LOG_ID: &'static str = #log_id;
91+
const LOG_ID_U64: u64 = #log_id_u64;
92+
}
93+
}
94+
});
95+
8196
quote! {
8297
#[allow(clippy::enum_variant_names)]
8398
#[derive(
@@ -95,5 +110,6 @@ fn enum_decl(
95110
#unused_generics_variant
96111
}
97112
#maybe_impl_error
113+
#log_impl
98114
}
99115
}

packages/fuels-code-gen/src/program_bindings/custom_types/structs.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,21 @@ use crate::{
2020
pub(crate) fn expand_custom_struct(
2121
type_decl: &FullTypeDeclaration,
2222
no_std: bool,
23+
log_id: Option<&String>,
2324
) -> Result<GeneratedCode> {
2425
let struct_type_path = type_decl.custom_type_path()?;
2526
let struct_ident = struct_type_path.ident().unwrap();
2627

2728
let components = Components::new(&type_decl.components, true, struct_type_path.parent())?;
2829
let generic_parameters = extract_generic_parameters(type_decl);
2930

30-
let code = struct_decl(struct_ident, &components, &generic_parameters, no_std);
31+
let code = struct_decl(
32+
struct_ident,
33+
&components,
34+
&generic_parameters,
35+
no_std,
36+
log_id,
37+
);
3138

3239
let struct_code = GeneratedCode::new(code, HashSet::from([struct_ident.into()]), no_std);
3340

@@ -52,6 +59,7 @@ fn struct_decl(
5259
components: &Components,
5360
generics: &[Ident],
5461
no_std: bool,
62+
log_id: Option<&String>,
5563
) -> TokenStream {
5664
let derive_default = components
5765
.is_empty()
@@ -64,6 +72,17 @@ fn struct_decl(
6472
let (phantom_fields, phantom_types) =
6573
components.generate_parameters_for_unused_generics(generics);
6674

75+
let log_impl = log_id.map(|log_id| {
76+
let log_id_u64: u64 = log_id.parse::<u64>().expect("log id should be a valid u64 string");
77+
78+
quote! {
79+
impl #generics_w_bounds ::fuels::core::codec::Log for #struct_ident #generics_wo_bounds {
80+
const LOG_ID: &'static str = #log_id;
81+
const LOG_ID_U64: u64 = #log_id_u64;
82+
}
83+
}
84+
});
85+
6786
quote! {
6887
#[derive(
6988
Clone,
@@ -89,5 +108,7 @@ fn struct_decl(
89108
}
90109
}
91110
}
111+
112+
#log_impl
92113
}
93114
}

packages/fuels-core/src/codec/logs.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ use std::{
55
iter::FilterMap,
66
};
77

8+
/// Trait that represents a log with a unique identifier.
9+
pub trait Log {
10+
/// Returns the unique identifier of the log as a string.
11+
const LOG_ID: &'static str;
12+
/// Returns the unique identifier of the log as a `u64`.
13+
const LOG_ID_U64: u64;
14+
}
15+
816
#[derive(Debug, Clone)]
917
pub struct ErrorDetails {
1018
pub(crate) pkg: String,

0 commit comments

Comments
 (0)