libmpv_client/types/
node.rs

1#![allow(non_upper_case_globals)]
2
3use std::collections::HashMap;
4use std::ffi::{c_void, CStr, CString, c_char};
5use std::fmt::Debug;
6use std::marker::PhantomData;
7use std::mem::MaybeUninit;
8use libmpv_client_sys::{mpv_byte_array, mpv_format_MPV_FORMAT_BYTE_ARRAY, mpv_format_MPV_FORMAT_DOUBLE, mpv_format_MPV_FORMAT_FLAG, mpv_format_MPV_FORMAT_INT64, mpv_format_MPV_FORMAT_NODE_ARRAY, mpv_format_MPV_FORMAT_NODE_MAP, mpv_format_MPV_FORMAT_NONE, mpv_format_MPV_FORMAT_STRING, mpv_node, mpv_node__bindgen_ty_1, mpv_node_list};
9use crate::*;
10use crate::byte_array::MpvByteArray;
11use crate::node_array::MpvNodeArray;
12use crate::node_map::MpvNodeMap;
13use crate::types::traits::{MpvFormat, MpvRecv, MpvRecvInternal, MpvRepr, MpvSend, MpvSendInternal, ToMpvRepr};
14
15/// Generic data storage for various mpv argument types and responses.
16#[derive(Debug, Clone, PartialEq)]
17pub enum Node {
18    /// The [`Node`] is empty. See [`Format::NONE`].
19    None,
20    /// The [`Node`] contains a string. See [`Format::STRING`].
21    String(String),
22    /// The [`Node`] contains a boolean flag. See [`Format::NONE`].
23    Flag(bool),
24    /// The [`Node`] contains an integer. See [`Format::INT64`].
25    Int64(i64),
26    /// The [`Node`] contains a double. See [`Format::DOUBLE`].
27    Double(f64),
28    /// The [`Node`] contains an array of [`Node`]s. See [`Format::NODE_ARRAY`].
29    Array(NodeArray),
30    /// The [`Node`] contains a map of [`String`] keys and [`Node`] values. See [`Format::NODE_MAP`].
31    Map(NodeMap),
32    /// The [`Node`] contains a raw, untyped byte array. See [`Format::BYTE_ARRAY`].
33    ByteArray(ByteArray),
34}
35
36#[derive(Debug)]
37pub(crate) struct MpvNode<'a> {
38    _original: PhantomData<&'a Node>,
39
40    _owned_cstring: Option<CString>,
41    _array_repr: Option<MpvNodeArray<'a>>,
42    _map_repr: Option<MpvNodeMap<'a>>,
43    _bytes_repr: Option<MpvByteArray<'a>>,
44
45    pub(crate) node: Box<mpv_node>,
46}
47
48impl MpvRepr for MpvNode<'_> {
49    type Repr = mpv_node;
50
51    fn ptr(&self) -> *const Self::Repr {
52        &raw const *self.node
53    }
54}
55
56impl MpvFormat for Node {
57    const MPV_FORMAT: Format = Format::NODE;
58}
59
60impl MpvRecv for Node {}
61impl MpvRecvInternal for Node {
62    unsafe fn from_ptr(ptr: *const c_void) -> Result<Self> {
63        unsafe { Self::from_node_ptr(ptr as *const mpv_node) }
64    }
65
66    unsafe fn from_mpv<F: Fn(*mut c_void) -> Result<i32>>(fun: F) -> Result<Self> {
67        let mut node: MaybeUninit<mpv_node> = MaybeUninit::uninit();
68
69        fun(node.as_mut_ptr() as *mut c_void).map(|_| {
70            let ret = unsafe { Self::from_node_ptr(node.as_ptr()) };
71            unsafe { mpv_free_node_contents(node.as_mut_ptr()) }
72            ret
73        })?
74    }
75}
76
77impl MpvSend for Node {}
78impl MpvSendInternal for Node {
79    fn to_mpv<F: Fn(*mut c_void) -> Result<i32>>(&self, fun: F) -> Result<i32> {
80        let repr = self.to_mpv_repr();
81
82        fun(repr.ptr() as *mut c_void)
83    }
84}
85
86impl ToMpvRepr for Node {
87    type ReprWrap<'a> = MpvNode<'a>;
88
89    fn to_mpv_repr(&self) -> Self::ReprWrap<'_> {
90        let mut repr = MpvNode {
91            _original: PhantomData,
92            _owned_cstring: None,
93            _array_repr: None,
94            _map_repr: None,
95            _bytes_repr: None,
96            node: Box::new(mpv_node { u: mpv_node__bindgen_ty_1 { int64: 0 }, format: 0 }),
97        };
98
99        match self {
100            Node::None => {
101                repr.node.u = mpv_node__bindgen_ty_1 { flag: 0 };
102                repr.node.format = mpv_format_MPV_FORMAT_NONE;
103            },
104            Node::String(x) => {
105                // TODO: Remove this unwrap() by converting to_mpv_repr to return Result<>. See traits.rs.
106                repr._owned_cstring = Some(CString::new(x.as_bytes()).unwrap_or_default());
107                let cstring_ptr = repr._owned_cstring.as_ref().unwrap().as_ptr(); // SAFETY: We just assigned Some.
108
109                repr.node.u = mpv_node__bindgen_ty_1 { string: cstring_ptr as *mut c_char };
110                repr.node.format = mpv_format_MPV_FORMAT_STRING;
111            }
112            Node::Flag(x) => {
113                repr.node.u = mpv_node__bindgen_ty_1 { flag: if *x { 1 } else { 0 } };
114                repr.node.format = mpv_format_MPV_FORMAT_FLAG;
115            }
116            Node::Int64(x) => {
117                repr.node.u = mpv_node__bindgen_ty_1 { int64: *x };
118                repr.node.format = mpv_format_MPV_FORMAT_INT64;
119            }
120            Node::Double(x) => {
121                repr.node.u = mpv_node__bindgen_ty_1 { double_: *x };
122                repr.node.format = mpv_format_MPV_FORMAT_DOUBLE;
123            }
124            Node::Array(x) => {
125                repr._array_repr = Some(x.to_mpv_repr());
126                let mpv_ptr = repr._array_repr.as_ref().unwrap().ptr(); // SAFETY: We just assigned Some.
127
128                repr.node.u = mpv_node__bindgen_ty_1 { list: mpv_ptr as *mut mpv_node_list };
129                repr.node.format = mpv_format_MPV_FORMAT_NODE_ARRAY;
130            }
131            Node::Map(x) => {
132                repr._map_repr = Some(x.to_mpv_repr());
133                let mpv_ptr = repr._map_repr.as_ref().unwrap().ptr(); // SAFETY: We just assigned Some.
134
135                repr.node.u = mpv_node__bindgen_ty_1 { list: mpv_ptr as *mut mpv_node_list };
136                repr.node.format = mpv_format_MPV_FORMAT_NODE_MAP;
137            }
138            Node::ByteArray(x) => {
139                repr._bytes_repr = Some(x.to_mpv_repr());
140                let mpv_ptr = repr._bytes_repr.as_ref().unwrap().ptr(); // SAFETY: We just assigned Some.
141
142                repr.node.u = mpv_node__bindgen_ty_1 { ba: mpv_ptr as *mut mpv_byte_array };
143                repr.node.format = mpv_format_MPV_FORMAT_BYTE_ARRAY;
144            }
145        };
146
147        repr
148    }
149}
150
151impl Node {
152    pub(crate) unsafe fn from_node_ptr(ptr: *const mpv_node) -> Result<Self> {
153        check_null!(ptr);
154        let node = unsafe { *ptr };
155
156        match node.format {
157            mpv_format_MPV_FORMAT_NONE => Ok(Node::None),
158            mpv_format_MPV_FORMAT_STRING => Ok(Node::String(unsafe { CStr::from_ptr(node.u.string) }.to_str()?.to_string())),
159            mpv_format_MPV_FORMAT_FLAG => Ok(Node::Flag(unsafe { node.u.flag } != 0)),
160            mpv_format_MPV_FORMAT_INT64 => Ok(Node::Int64(unsafe { node.u.int64 })),
161            mpv_format_MPV_FORMAT_DOUBLE => Ok(Node::Double(unsafe { node.u.double_ })),
162            mpv_format_MPV_FORMAT_NODE_ARRAY => Ok(Node::Array(unsafe { NodeArray::from_ptr(node.u.list as *const c_void)? })),
163            mpv_format_MPV_FORMAT_NODE_MAP => Ok(Node::Map(unsafe { NodeMap::from_ptr(node.u.list as *const c_void)? })),
164            mpv_format_MPV_FORMAT_BYTE_ARRAY => Ok(Node::ByteArray(unsafe { ByteArray::from_ptr(node.u.ba as *const c_void)? })),
165            _ => unimplemented!()
166        }
167    }
168}
169
170impl From<&[(&str, Node)]> for Node {
171    /// Convenience function to create a [`Node::Map`] from a [`&[(&str, Node)]`] slice.
172    ///
173    /// This creates the underlying [`HashMap`] and clones the references [`Node`]s.
174    fn from(slice: &[(&str, Node)]) -> Self {
175        let map: HashMap<String, Node> = slice.iter()
176            .map(|(k, v)| (k.to_string(), v.clone()))
177            .collect();
178        Node::Map(map)
179    }
180}
181
182impl From<&[Node]> for Node {
183    /// Convenience function to create a [`Node::Map`] from a [`&[Node]`] slice.
184    ///
185    /// This creates the underlying [`Vec`].
186    fn from(slice: &[Node]) -> Self {
187        Node::Array(slice.to_vec())
188    }
189}