gobject_ast/model/types/
signal.rs1use serde::Serialize;
2
3use crate::model::{
4 doc::SignalDoc,
5 expression::{CallExpression, Expression, StructField},
6 types::GType,
7};
8
9#[derive(Debug, Clone, Serialize)]
25pub struct Signal {
26 pub name: String,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub enum_value: Option<String>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub doc: Option<SignalDoc>,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub itype: Option<String>, #[serde(skip_serializing_if = "Vec::is_empty")]
34 pub flags: Vec<SignalFlag>,
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub class_offset: Option<StructField>, #[serde(skip_serializing_if = "Option::is_none")]
38 pub accumulator: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
40 pub accu_data: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
42 pub c_marshaller: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
44 pub return_type: Option<GType>,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub n_params: Option<i64>,
47 #[serde(skip_serializing_if = "Vec::is_empty")]
48 pub param_types: Vec<GType>,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
52#[serde(rename_all = "snake_case")]
53pub enum SignalFlag {
54 RunFirst,
55 RunLast,
56 RunCleanup,
57 NoRecurse,
58 Detailed,
59 Action,
60 NoHooks,
61 MustCollect,
62 Deprecated,
63 AccumulatorFirstRun,
64 Unknown(String),
65}
66
67impl SignalFlag {
68 pub fn from_identifier(s: &str) -> Self {
69 match s {
70 "G_SIGNAL_RUN_FIRST" => Self::RunFirst,
71 "G_SIGNAL_RUN_LAST" => Self::RunLast,
72 "G_SIGNAL_RUN_CLEANUP" => Self::RunCleanup,
73 "G_SIGNAL_NO_RECURSE" => Self::NoRecurse,
74 "G_SIGNAL_DETAILED" => Self::Detailed,
75 "G_SIGNAL_ACTION" => Self::Action,
76 "G_SIGNAL_NO_HOOKS" => Self::NoHooks,
77 "G_SIGNAL_MUST_COLLECT" => Self::MustCollect,
78 "G_SIGNAL_DEPRECATED" => Self::Deprecated,
79 "G_SIGNAL_ACCUMULATOR_FIRST_RUN" => Self::AccumulatorFirstRun,
80 _ => Self::Unknown(s.to_owned()),
81 }
82 }
83
84 pub fn as_str(&self) -> &str {
85 match self {
86 Self::RunFirst => "G_SIGNAL_RUN_FIRST",
87 Self::RunLast => "G_SIGNAL_RUN_LAST",
88 Self::RunCleanup => "G_SIGNAL_RUN_CLEANUP",
89 Self::NoRecurse => "G_SIGNAL_NO_RECURSE",
90 Self::Detailed => "G_SIGNAL_DETAILED",
91 Self::Action => "G_SIGNAL_ACTION",
92 Self::NoHooks => "G_SIGNAL_NO_HOOKS",
93 Self::MustCollect => "G_SIGNAL_MUST_COLLECT",
94 Self::Deprecated => "G_SIGNAL_DEPRECATED",
95 Self::AccumulatorFirstRun => "G_SIGNAL_ACCUMULATOR_FIRST_RUN",
96 Self::Unknown(s) => s,
97 }
98 }
99}
100
101impl Signal {
102 pub fn from_g_signal_new_call(call: &CallExpression, source: &[u8]) -> Option<Self> {
114 if !call.function_name(source).starts_with("g_signal_new") {
115 return None;
116 }
117
118 let name = call.extract_string_from_arg(0)?;
120
121 let itype = call.get_arg_text(1, source).map(ToOwned::to_owned);
123
124 let flags = call
126 .get_arg(2)
127 .map(extract_signal_flags)
128 .unwrap_or_default();
129
130 let class_offset = call.get_arg(3).and_then(|expr| match expr {
132 Expression::Call(offset_call)
133 if offset_call.function_name(source) == "G_STRUCT_OFFSET" =>
134 {
135 let struct_type = offset_call.get_arg(0).and_then(|e| {
136 if let Expression::Identifier(id) = e {
137 Some(id.name.clone())
138 } else {
139 None
140 }
141 })?;
142 let field = offset_call.get_arg(1).and_then(|e| {
143 if let Expression::Identifier(id) = e {
144 Some(id.name.clone())
145 } else {
146 None
147 }
148 })?;
149 Some(StructField { struct_type, field })
150 }
151 _ => None, });
153
154 let accumulator = call.get_arg_text(4, source).map(ToOwned::to_owned);
156
157 let accu_data = call.get_arg_text(5, source).map(ToOwned::to_owned);
159
160 let c_marshaller = call.get_arg_text(6, source).map(ToOwned::to_owned);
162
163 let return_type = call
165 .get_arg(7)
166 .and_then(|e| GType::from_expression(e, source));
167
168 let n_params = call.get_arg(8).and_then(|expr| match expr {
170 Expression::NumberLiteral(n) => n.value.parse::<i64>().ok(),
171 _ => None,
172 });
173
174 let param_types = (9..call.arguments.len())
176 .filter_map(|i| {
177 call.get_arg(i)
178 .and_then(|e| GType::from_expression(e, source))
179 })
180 .collect();
181
182 Some(Self {
183 name,
184 enum_value: None,
185 doc: None,
186 itype,
187 flags,
188 class_offset,
189 accumulator,
190 accu_data,
191 c_marshaller,
192 return_type,
193 n_params,
194 param_types,
195 })
196 }
197}
198
199fn extract_signal_flags(expr: &Expression) -> Vec<SignalFlag> {
201 let mut flags = Vec::new();
202
203 expr.walk(&mut |e| {
207 if let Expression::Identifier(id) = e
208 && id.name.starts_with("G_SIGNAL_")
209 {
210 flags.push(SignalFlag::from_identifier(&id.name));
211 }
212 });
213
214 flags
215}