libmpv_client/types/
node_map.rs

1use std::collections::HashMap;
2use std::ffi::{CStr, CString,c_char, c_int, c_void};
3use std::marker::PhantomData;
4use std::mem::MaybeUninit;
5use std::ptr::null_mut;
6use libmpv_client_sys::{mpv_node, mpv_node_list};
7use crate::*;
8use crate::node::MpvNode;
9use crate::types::traits::{MpvFormat, MpvRecv, MpvRecvInternal, MpvRepr, MpvSend, MpvSendInternal, ToMpvRepr};
10
11/// A [`HashMap<String, Node>`], used only within a [`Node`], and only in specific situations.
12pub type NodeMap = HashMap<String, Node>;
13
14#[derive(Debug)]
15pub(crate) struct MpvNodeMap<'a> {
16    _original: PhantomData<&'a NodeMap>,
17
18    _owned_reprs: Vec<MpvNode<'a>>,
19    _flat_reprs: Vec<mpv_node>,
20
21    _owned_keys: Vec<CString>,
22    _flat_keys: Vec<*const c_char>,
23
24    node_list: Box<mpv_node_list>,
25}
26
27impl MpvRepr for MpvNodeMap<'_> {
28    type Repr = mpv_node_list;
29
30    fn ptr(&self) -> *const Self::Repr {
31        &raw const *self.node_list
32    }
33}
34
35impl MpvFormat for NodeMap {
36    const MPV_FORMAT: Format = Format::NODE_MAP;
37}
38
39impl From<NodeMap> for Node {
40    fn from(value: NodeMap) -> Self {
41        Node::Map(value)
42    }
43}
44
45impl From<&NodeMap> for Node {
46    fn from(value: &NodeMap) -> Self {
47        Node::Map(value.clone())
48    }
49}
50
51impl MpvRecv for NodeMap {}
52impl MpvRecvInternal for NodeMap {
53    unsafe fn from_ptr(ptr: *const c_void) -> Result<Self> {
54        check_null!(ptr);
55
56        let node_list = unsafe { *(ptr as *const mpv_node_list) };
57
58        check_null!(node_list.values);
59        check_null!(node_list.keys);
60
61        let mut values = Vec::with_capacity(node_list.num as usize);
62        let mut keys = Vec::with_capacity(node_list.num as usize);
63
64        let node_values = unsafe { std::slice::from_raw_parts(node_list.values, node_list.num as usize) };
65        for node_value in node_values {
66            values.push(unsafe { Node::from_node_ptr(node_value)? });
67        }
68
69        let node_keys = unsafe { std::slice::from_raw_parts(node_list.keys, node_list.num as usize) };
70        for node_key in node_keys {
71            keys.push(unsafe { CStr::from_ptr(*node_key) }.to_str()?.to_string());
72        }
73
74        let map = keys.into_iter().zip(values).collect();
75
76        Ok(map)
77    }
78
79    unsafe fn from_mpv<F: Fn(*mut c_void) -> Result<i32>>(fun: F) -> Result<Self> {
80        let mut node_list: MaybeUninit<mpv_node_list> = MaybeUninit::uninit();
81
82        fun(node_list.as_mut_ptr() as *mut c_void).map(|_| {
83            unsafe { Self::from_ptr(node_list.as_ptr() as *const c_void) }
84        })?
85    }
86}
87
88impl MpvSend for NodeMap {}
89impl MpvSendInternal for NodeMap {
90    fn to_mpv<F: Fn(*mut c_void) -> Result<i32>>(&self, fun: F) -> Result<i32> {
91        let repr = self.to_mpv_repr();
92
93        fun(repr.ptr() as *mut c_void)
94    }
95}
96
97impl ToMpvRepr for NodeMap {
98    type ReprWrap<'a> = MpvNodeMap<'a>;
99
100    fn to_mpv_repr(&self) -> Self::ReprWrap<'_> {
101        let mut repr = MpvNodeMap {
102            _original: PhantomData,
103            _owned_reprs: Vec::with_capacity(self.len()),
104            _flat_reprs: Vec::with_capacity(self.len()),
105            _owned_keys: Vec::with_capacity(self.len()),
106            _flat_keys: Vec::with_capacity(self.len()),
107            node_list: Box::new(mpv_node_list {
108                num: self.len() as c_int,
109                values: null_mut(),
110                keys: null_mut(),
111            }),
112        };
113
114        for (key, value) in self {
115            // TODO: Remove this unwrap() by converting to_mpv_repr to return Result<>. See traits.rs.
116            let cstring = CString::new(key.as_bytes()).unwrap_or_default();
117            repr._flat_keys.push(cstring.as_ptr());
118            repr._owned_keys.push(cstring);
119
120            let val_repr = value.to_mpv_repr();
121            repr._flat_reprs.push(*val_repr.node);
122            repr._owned_reprs.push(val_repr);
123        }
124
125        repr.node_list.values = repr._flat_reprs.as_ptr() as *mut _;
126        repr.node_list.keys = repr._flat_keys.as_ptr() as *mut _;
127
128        repr
129    }
130}