fuels_code_gen/program_bindings/abigen/
abigen_target.rs1use 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}