Skip to main content

mpv_client_cross/
node.rs

1use super::{
2    mpv_byte_array, mpv_format_MPV_FORMAT_BYTE_ARRAY, mpv_format_MPV_FORMAT_DOUBLE, mpv_format_MPV_FORMAT_FLAG,
3    mpv_format_MPV_FORMAT_INT64, mpv_format_MPV_FORMAT_NODE_ARRAY, mpv_format_MPV_FORMAT_NODE_MAP,
4    mpv_format_MPV_FORMAT_NONE, mpv_format_MPV_FORMAT_STRING, mpv_node, mpv_node__bindgen_ty_1, mpv_node_list,
5};
6use std::collections::HashMap;
7use std::ffi::{c_char, CStr, CString};
8use std::ptr;
9use std::slice;
10
11#[derive(Debug, Clone, Default)]
12pub enum Node {
13    #[default]
14    None,
15    String(String),
16    Int(i64),
17    Double(f64),
18    Bool(bool),
19    ByteArray(Vec<u8>),
20    Array(Vec<Node>),
21    Map(HashMap<String, Node>),
22}
23
24pub fn from_mpv_node(node: &mut mpv_node) -> Node {
25    match node.format {
26        mpv_format_MPV_FORMAT_STRING => {
27            Node::String(unsafe { CStr::from_ptr(node.u.string) }.to_string_lossy().into_owned())
28        }
29        mpv_format_MPV_FORMAT_INT64 => Node::Int(unsafe { node.u.int64 }),
30        mpv_format_MPV_FORMAT_DOUBLE => Node::Double(unsafe { node.u.double_ }),
31        mpv_format_MPV_FORMAT_FLAG => Node::Bool(unsafe { node.u.flag } != 0),
32        mpv_format_MPV_FORMAT_NODE_ARRAY => {
33            let list = unsafe { &*node.u.list };
34            let values = unsafe { slice::from_raw_parts_mut(list.values, list.num as usize) };
35            Node::Array(values.iter_mut().map(from_mpv_node).collect())
36        }
37        mpv_format_MPV_FORMAT_NODE_MAP => {
38            let list = unsafe { &*node.u.list };
39            let values = unsafe { slice::from_raw_parts_mut(list.values, list.num as usize) };
40            let keys = unsafe { slice::from_raw_parts(list.keys, list.num as usize) };
41            let map = keys
42                .iter()
43                .zip(values.iter_mut())
44                .filter_map(|(&k, v)| {
45                    unsafe { k.as_ref() }.map(|key_ptr| {
46                        let key = unsafe { CStr::from_ptr(key_ptr) }.to_string_lossy().into_owned();
47                        (key, from_mpv_node(v))
48                    })
49                })
50                .collect();
51            Node::Map(map)
52        }
53        mpv_format_MPV_FORMAT_BYTE_ARRAY => {
54            let arr: &mpv_byte_array = unsafe { &*node.u.ba };
55            let data = unsafe { slice::from_raw_parts(arr.data as *const u8, arr.size) };
56            Node::ByteArray(data.to_vec())
57        }
58        _ => Node::None,
59    }
60}
61
62pub fn to_mpv_node(node: &Node) -> *mut mpv_node {
63    let mut mpv_node = Box::new(mpv_node {
64        format: 0,
65        u: mpv_node__bindgen_ty_1 { int64: 0 },
66    });
67
68    match node {
69        Node::None => {
70            mpv_node.format = mpv_format_MPV_FORMAT_NONE;
71        }
72        Node::String(s) => {
73            mpv_node.format = mpv_format_MPV_FORMAT_STRING;
74            let cstr = CString::new(s.as_str()).expect("CString::new failed");
75            mpv_node.u.string = cstr.into_raw();
76        }
77        Node::Int(i) => {
78            mpv_node.format = mpv_format_MPV_FORMAT_INT64;
79            mpv_node.u.int64 = *i;
80        }
81        Node::Double(f) => {
82            mpv_node.format = mpv_format_MPV_FORMAT_DOUBLE;
83            mpv_node.u.double_ = *f;
84        }
85        Node::Bool(b) => {
86            mpv_node.format = mpv_format_MPV_FORMAT_FLAG;
87            mpv_node.u.flag = if *b { 1 } else { 0 };
88        }
89        Node::Array(arr) => {
90            mpv_node.format = mpv_format_MPV_FORMAT_NODE_ARRAY;
91            let values: Vec<_> = arr.iter().map(to_mpv_node).collect();
92            let list = Box::new(mpv_node_list {
93                num: values.len() as i32,
94                values: Box::into_raw(values.into_boxed_slice()) as *mut mpv_node,
95                keys: std::ptr::null_mut(),
96            });
97            mpv_node.u.list = Box::into_raw(list);
98        }
99        Node::Map(map) => {
100            mpv_node.format = mpv_format_MPV_FORMAT_NODE_MAP;
101            let (keys, values): (Vec<_>, Vec<_>) = map
102                .iter()
103                .map(|(k, v)| {
104                    let ckey = CString::new(k.as_str()).expect("CString::new failed");
105                    (ckey.into_raw(), to_mpv_node(v))
106                })
107                .unzip();
108
109            let list = Box::new(mpv_node_list {
110                num: keys.len() as i32,
111                keys: Box::into_raw(keys.into_boxed_slice()) as *mut *mut c_char,
112                values: Box::into_raw(values.into_boxed_slice()) as *mut mpv_node,
113            });
114            mpv_node.u.list = Box::into_raw(list);
115        }
116        Node::ByteArray(vec) => {
117            mpv_node.format = mpv_format_MPV_FORMAT_BYTE_ARRAY;
118            let ba = Box::new(mpv_byte_array {
119                size: vec.len(),
120                data: unsafe { libc::malloc(vec.len()) },
121            });
122            if ba.data.is_null() {
123                panic!("Failed to allocate memory for byte array");
124            }
125            unsafe {
126                ptr::copy_nonoverlapping(vec.as_ptr(), ba.data as *mut u8, vec.len());
127            }
128            mpv_node.u.ba = Box::into_raw(ba);
129        }
130    }
131
132    Box::into_raw(mpv_node)
133}