gobject_ast/model/types/
signal.rs1use serde::Serialize;
2
3use crate::model::{
4 doc::SignalDoc,
5 expression::{CallExpression, Expression, OffsetField},
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<OffsetField>, #[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) -> Option<Self> {
114 if !call.function_name().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).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) if offset_call.function_name() == "G_STRUCT_OFFSET" => {
133 let struct_type = offset_call.get_arg(0).and_then(|e| {
134 if let Expression::Identifier(id) = e {
135 Some(id.name.clone())
136 } else {
137 None
138 }
139 })?;
140 let field = offset_call.get_arg(1).and_then(|e| {
141 if let Expression::Identifier(id) = e {
142 Some(id.name.clone())
143 } else {
144 None
145 }
146 })?;
147 Some(OffsetField { struct_type, field })
148 }
149 _ => None, });
151
152 let accumulator = call.get_arg_text(4).map(ToOwned::to_owned);
154
155 let accu_data = call.get_arg_text(5).map(ToOwned::to_owned);
157
158 let c_marshaller = call.get_arg_text(6).map(ToOwned::to_owned);
160
161 let return_type = call.get_arg(7).and_then(GType::from_expression);
163
164 let n_params = call.get_arg(8).and_then(|expr| match expr {
166 Expression::NumberLiteral(n) => n.value.parse::<i64>().ok(),
167 _ => None,
168 });
169
170 let param_types = (9..call.arguments.len())
172 .filter_map(|i| call.get_arg(i).and_then(GType::from_expression))
173 .collect();
174
175 Some(Self {
176 name,
177 enum_value: None,
178 doc: None,
179 itype,
180 flags,
181 class_offset,
182 accumulator,
183 accu_data,
184 c_marshaller,
185 return_type,
186 n_params,
187 param_types,
188 })
189 }
190}
191
192fn extract_signal_flags(expr: &Expression) -> Vec<SignalFlag> {
194 let mut flags = Vec::new();
195
196 expr.walk(&mut |e| {
200 if let Expression::Identifier(id) = e
201 && id.name.starts_with("G_SIGNAL_")
202 {
203 flags.push(SignalFlag::from_identifier(&id.name));
204 }
205 });
206
207 flags
208}