fuels_code_gen/program_bindings/abigen/
abigen_target.rs

1use std::{
2    convert::TryFrom,
3    env, fs,
4    path::{Path, PathBuf},
5    str::FromStr,
6};
7
8use fuel_abi_types::abi::full_program::FullProgramABI;
9use proc_macro2::Ident;
10
11use crate::error::{error, Error, Result};
12
13#[derive(Debug, Clone)]
14pub struct AbigenTarget {
15    pub(crate) name: String,
16    pub(crate) source: Abi,
17    pub(crate) program_type: ProgramType,
18}
19
20impl AbigenTarget {
21    pub fn new(name: String, source: Abi, program_type: ProgramType) -> Self {
22        Self {
23            name,
24            source,
25            program_type,
26        }
27    }
28
29    pub fn name(&self) -> &str {
30        &self.name
31    }
32
33    pub fn source(&self) -> &Abi {
34        &self.source
35    }
36
37    pub fn program_type(&self) -> ProgramType {
38        self.program_type
39    }
40}
41
42#[derive(Debug, Clone)]
43pub struct Abi {
44    pub(crate) path: Option<PathBuf>,
45    pub(crate) abi: FullProgramABI,
46}
47
48impl Abi {
49    pub fn load_from(path: impl AsRef<Path>) -> Result<Abi> {
50        let path = Self::canonicalize_path(path.as_ref())?;
51
52        let json_abi = fs::read_to_string(&path).map_err(|e| {
53            error!(
54                "failed to read `abi` file with path {}: {}",
55                path.display(),
56                e
57            )
58        })?;
59        let abi = Self::parse_from_json(&json_abi)?;
60
61        Ok(Abi {
62            path: Some(path),
63            abi,
64        })
65    }
66
67    fn canonicalize_path(path: &Path) -> Result<PathBuf> {
68        let current_dir = env::current_dir()
69            .map_err(|e| error!("unable to get current directory: ").combine(e))?;
70
71        let root = current_dir.canonicalize().map_err(|e| {
72            error!(
73                "unable to canonicalize current directory {}: ",
74                current_dir.display()
75            )
76            .combine(e)
77        })?;
78
79        let path = root.join(path);
80
81        if path.is_relative() {
82            path.canonicalize().map_err(|e| {
83                error!(
84                    "unable to canonicalize file from working dir {} with path {}: {}",
85                    env::current_dir()
86                        .map(|cwd| cwd.display().to_string())
87                        .unwrap_or_else(|err| format!("??? ({err})")),
88                    path.display(),
89                    e
90                )
91            })
92        } else {
93            Ok(path)
94        }
95    }
96
97    fn parse_from_json(json_abi: &str) -> Result<FullProgramABI> {
98        FullProgramABI::from_json_abi(json_abi)
99            .map_err(|e| error!("malformed `abi`. Did you use `forc` to create it?: ").combine(e))
100    }
101
102    pub fn path(&self) -> Option<&PathBuf> {
103        self.path.as_ref()
104    }
105
106    pub fn abi(&self) -> &FullProgramABI {
107        &self.abi
108    }
109}
110
111impl FromStr for Abi {
112    type Err = Error;
113
114    fn from_str(json_abi: &str) -> Result<Self> {
115        let abi = Abi::parse_from_json(json_abi)?;
116
117        Ok(Abi { path: None, abi })
118    }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub enum ProgramType {
123    Script,
124    Contract,
125    Predicate,
126}
127
128impl FromStr for ProgramType {
129    type Err = Error;
130
131    fn from_str(string: &str) -> std::result::Result<Self, Self::Err> {
132        let program_type = match string {
133            "Script" => ProgramType::Script,
134            "Contract" => ProgramType::Contract,
135            "Predicate" => ProgramType::Predicate,
136            _ => {
137                return Err(error!(
138                    "`{string}` is not a valid program type. Expected one of: `Script`, `Contract`, `Predicate`"
139                ))
140            }
141        };
142
143        Ok(program_type)
144    }
145}
146
147impl TryFrom<Ident> for ProgramType {
148    type Error = syn::Error;
149
150    fn try_from(ident: Ident) -> std::result::Result<Self, Self::Error> {
151        ident
152            .to_string()
153            .as_str()
154            .parse()
155            .map_err(|e| Self::Error::new(ident.span(), e))
156    }
157}