Skip to content

Commit 983c460

Browse files
committed
feat: refactor Node and NodeContent structures for improved type handling and memory efficiency
1 parent 7a0f1f6 commit 983c460

2 files changed

Lines changed: 85 additions & 46 deletions

File tree

src/events/types.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use pyo3::sync::PyOnceLock;
1111
use whatsapp_rust::types::message::{MessageInfo as WhatsappMessageInfo};
1212
use crate::types::{JID, MessageInfo, MessageSource};
1313
use crate::wacore::node::{Node, NodeContent, NodeValue};
14-
1514
static WHATSAPP_MESSAGE_PROTO: PyOnceLock<Py<PyType>> = PyOnceLock::new();
1615
static SYNC_ACTION_VALUE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
1716
fn get_proto_import(py: Python<'_>, import: &str, attr: &str) -> PyResult<Py<PyType>>{

src/wacore/node.rs

Lines changed: 85 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
use std::ops::Deref;
2-
3-
use pyo3::types::{PyList, PyString};
4-
use pyo3::{Python, pyclass, pymethods, types::PyBytes};
1+
use pyo3::types::PyString;
2+
use pyo3::{Python, pyclass, pymethods};
53
use pyo3::{IntoPyObjectExt, prelude::*};
64
use whatsapp_rust::NodeBuilder;
75
use crate::types::JID;
@@ -69,9 +67,9 @@ impl NodeValue {
6967

7068
/// NodeContent enum internal
7169
pub enum NodeContentEnum {
72-
Bytes(Py<PyBytes>),
73-
String(Py<PyString>),
74-
Nodes(Py<PyList>), // PyList<Node>
70+
Bytes(Py<Vec<u8>>),
71+
String(String),
72+
Nodes(Vec<Py<Node>>), // PyList<Node>
7573
}
7674

7775
/// PyClass wrapper untuk NodeContent
@@ -84,11 +82,12 @@ pub struct NodeContent {
8482
impl NodeContent {
8583
#[getter]
8684
fn value(&self, py: Python<'_>) -> Py<PyAny> {
87-
match &self.inner {
85+
let result = match &self.inner {
8886
NodeContentEnum::Bytes(b) => b.clone_ref(py).into_any(),
89-
NodeContentEnum::String(s) => s.clone_ref(py).into_any(),
90-
NodeContentEnum::Nodes(n) => n.clone_ref(py).into_any(),
91-
}
87+
NodeContentEnum::String(s) => s.into_py_any(py).unwrap(),
88+
NodeContentEnum::Nodes(n) => n.into_py_any(py).unwrap(),
89+
};
90+
result
9291
}
9392

9493
pub fn is_bytes(&self) -> bool {
@@ -103,13 +102,14 @@ impl NodeContent {
103102
matches!(self.inner, NodeContentEnum::Nodes(_))
104103
}
105104

106-
// pub fn __repr__(&self, py: Python<'_>) -> String {
107-
// match &self.inner {
108-
// NodeContentEnum::Bytes(_) => "NodeContent::Bytes(...)".to_string(),
109-
// NodeContentEnum::String(s) => format!("NodeContent::String({})", s),
110-
// NodeContentEnum::Nodes(n) => format!("NodeContent::Nodes(len={})", n.len()),
111-
// }
112-
// }
105+
pub fn __repr__(&self, _py: Python<'_>) -> PyResult<String> {
106+
let repr = match &self.inner {
107+
NodeContentEnum::Bytes(_) => "NodeContent::Bytes(...)".to_string(),
108+
NodeContentEnum::String(s) => format!("NodeContent::String({})", s),
109+
NodeContentEnum::Nodes(n) => format!("NodeContent::Nodes(len={})", n.len()),
110+
};
111+
Ok(repr)
112+
}
113113
}
114114

115115

@@ -118,40 +118,34 @@ pub struct Attrs {
118118
#[pyo3(get, set)]
119119
pub key: String,
120120
#[pyo3(get, set)]
121-
pub value: pyo3::Py<PyList>, // PyList<NodeValue>
121+
pub value: Vec<pyo3::Py<NodeValue>>, // PyList<NodeValue>
122122

123123
}
124+
#[pymethods]
125+
impl Attrs {
126+
#[new]
127+
fn new(key: String, value: Vec<Py<NodeValue>>) -> Self {
128+
Attrs {
129+
key: key,
130+
value: value
131+
}
132+
}
133+
}
124134
#[pyclass]
125135
pub struct Node {
126136
#[pyo3(get, set)]
127137
pub tag: String,
128138
#[pyo3(get, set)]
129-
pub attrs: Py<PyList>, // PyList<Attrs>
139+
pub attrs: Vec<Py<Attrs>>, // PyList<Attrs>
130140
#[pyo3(get, set)]
131-
pub content: Py<PyAny>, // Py<PyAny> yang bisa berisi NodeContent atau None
141+
pub content: Option<Py<NodeContent>>, // Py<PyAny> yang bisa berisi NodeContent atau None
132142
}
133143

134144
#[pymethods]
135145
impl Node {
136146
#[new]
137-
pub fn new(tag: String, attrs: Option<Py<PyList>>, content: Option<pyo3::Py<NodeContent>>) -> PyResult<Self> {
138-
Python::attach(|py| {
139-
let content_py = match content {
140-
Some(c) => c.into_any(),
141-
None => py.None(),
142-
};
143-
let attrs_py = match attrs {
144-
Some(a) => {
145-
let list = a.clone_ref(py);
146-
for item in list.bind(py).iter() {
147-
let _ = item.extract::<Py<Attrs>>()?;
148-
};
149-
list
150-
},
151-
None => PyList::empty(py).unbind(),
152-
};
153-
Ok(Self { tag, attrs: attrs_py, content: content_py })
154-
})
147+
pub fn new(tag: String, attrs: Vec<Py<Attrs>>, content: Option<pyo3::Py<NodeContent>>) -> Self {
148+
Self { tag, attrs: attrs, content: content }
155149
}
156150

157151
// pub fn __repr__(&self, py: Python<'_>) -> String {
@@ -167,6 +161,7 @@ impl Node {
167161
impl Node {
168162
pub fn to_node_builder(&self, py: Python<'_>) -> NodeBuilder {
169163
let mut builder = NodeBuilder::new(self.tag.clone());
164+
170165
if let Some(content) = &self.content {
171166
let content_ref = content.bind(py).borrow();
172167
match &content_ref.inner {
@@ -175,21 +170,66 @@ impl Node {
175170
builder = builder.bytes(b_extract);
176171
}
177172
NodeContentEnum::String(s) => {
178-
let s_extract = s.to_str(py).unwrap();
179-
builder = builder.string_content(s_extract);
173+
builder = builder.string_content(s.clone());
180174
}
181175
NodeContentEnum::Nodes(n) => {
182-
n.bind(py).iter().for_each(|item| {
183-
let it= item.extract();
184-
});
176+
let nodes_extract = n
177+
.iter()
178+
.map(|node| {
179+
let node_ref = node.bind(py).borrow();
180+
node_ref.to_node_builder(py).build()
181+
})
182+
.collect::<Vec<_>>();
183+
builder = builder.children(nodes_extract);
185184
}
185+
};
186+
}
187+
188+
for attr in &self.attrs {
189+
let attr_ref = attr.bind(py).borrow();
190+
if attr_ref.value.len() == 1 {
191+
let value_ref = attr_ref.value[0].bind(py).borrow();
192+
builder = match &value_ref.inner {
193+
NodeValueEnum::String(s) => builder.attr(attr_ref.key.clone(), s.clone()),
194+
NodeValueEnum::Jid(jid) => {
195+
let jid_ref = jid.bind(py).borrow();
196+
builder.jid_attr(attr_ref.key.clone(), jid_ref.as_whatsapp_jid())
197+
}
198+
};
199+
} else {
200+
let joined = attr_ref
201+
.value
202+
.iter()
203+
.map(|v| {
204+
let v_ref = v.bind(py).borrow();
205+
match &v_ref.inner {
206+
NodeValueEnum::String(s) => s.clone(),
207+
NodeValueEnum::Jid(jid) => {
208+
let jid_ref = jid.bind(py).borrow();
209+
jid_ref.as_whatsapp_jid().to_string()
210+
}
211+
}
212+
})
213+
.collect::<Vec<_>>()
214+
.join(",");
215+
builder = builder.attr(attr_ref.key.clone(), joined);
186216
}
187217
}
218+
188219
builder
189220
}
221+
190222
pub fn from_node_builder(builder: NodeBuilder) -> Self {
191223
let node = builder.build();
192-
Self { tag: node.tag, content: node.content }
193224

225+
Self {
226+
tag: node.tag,
227+
attrs: Vec::new(),
228+
content: None,
229+
}
230+
}
231+
232+
pub fn from_node(node: wacore_binary::node::Node) -> Self {
233+
//
194234
}
195235
}

0 commit comments

Comments
 (0)