use crate::pipewire::pw_parser::PwParser;
use crate::pipewire::pw_pod::PW_COMMAND_Node;
use crate::pipewire::pw_pod::PW_OBJECT_Format;
use crate::pipewire::pw_pod::PW_OBJECT_ParamBuffers;
use crate::pipewire::pw_pod::PW_OBJECT_ParamIO;
use crate::pipewire::pw_pod::PW_OBJECT_ParamLatency;
use crate::pipewire::pw_pod::PW_OBJECT_ParamMeta;
use crate::pipewire::pw_pod::PW_OBJECT_ParamPortConfig;
use crate::pipewire::pw_pod::PW_OBJECT_ParamProcessLatency;
use crate::pipewire::pw_pod::PW_OBJECT_ParamProfile;
use crate::pipewire::pw_pod::PW_OBJECT_ParamRoute;
use crate::pipewire::pw_pod::PW_OBJECT_Profiler;
use crate::pipewire::pw_pod::PW_OBJECT_PropInfo;
use crate::pipewire::pw_pod::PW_OBJECT_Props;
use crate::pipewire::pw_pod::PW_TYPE_Id;
use crate::pipewire::pw_pod::PwPod;
use crate::pipewire::pw_pod::PwPodArray;
use crate::pipewire::pw_pod::PwPodObject;
use crate::pipewire::pw_pod::PwPodObjectType;
use crate::pipewire::pw_pod::PwPodSequence;
use crate::pipewire::pw_pod::PwPodStruct;
use crate::pipewire::pw_pod::PwPodType;
use crate::pipewire::pw_pod::PwProp;
use crate::pipewire::pw_pod::SPA_FORMAT_AUDIO_bitorder;
use crate::pipewire::pw_pod::SPA_FORMAT_AUDIO_format;
use crate::pipewire::pw_pod::SPA_FORMAT_AUDIO_iec958Codec;
use crate::pipewire::pw_pod::SPA_FORMAT_AUDIO_position;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_H264_alignment;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_H264_streamFormat;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_chromaSite;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_colorMatrix;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_colorPrimaries;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_colorRange;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_format;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_interlaceMode;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_multiviewFlags;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_multiviewMode;
use crate::pipewire::pw_pod::SPA_FORMAT_VIDEO_transferFunction;
use crate::pipewire::pw_pod::SPA_FORMAT_mediaSubtype;
use crate::pipewire::pw_pod::SPA_FORMAT_mediaType;
use crate::pipewire::pw_pod::SPA_PARAM_BUFFERS_dataType;
use crate::pipewire::pw_pod::SPA_PARAM_IO_id;
use crate::pipewire::pw_pod::SPA_PARAM_META_type;
use crate::pipewire::pw_pod::SPA_PARAM_PORT_CONFIG_direction;
use crate::pipewire::pw_pod::SPA_PARAM_PORT_CONFIG_mode;
use crate::pipewire::pw_pod::SPA_PARAM_PROFILE_available;
use crate::pipewire::pw_pod::SPA_PARAM_ROUTE_available;
use crate::pipewire::pw_pod::SPA_PARAM_ROUTE_direction;
use crate::pipewire::pw_pod::SPA_PROP_channelMap;
use crate::pipewire::pw_pod::SPA_PROP_iec958Codecs;
use crate::pipewire::pw_pod::SpaAudioChannel;
use crate::pipewire::pw_pod::SpaAudioFormat;
use crate::pipewire::pw_pod::SpaAudioIec958Codec;
use crate::pipewire::pw_pod::SpaDataTypes;
use crate::pipewire::pw_pod::SpaDirection;
use crate::pipewire::pw_pod::SpaFormat;
use crate::pipewire::pw_pod::SpaH264Alignment;
use crate::pipewire::pw_pod::SpaH264StreamFormat;
use crate::pipewire::pw_pod::SpaIoType;
use crate::pipewire::pw_pod::SpaMediaSubtype;
use crate::pipewire::pw_pod::SpaMediaType;
use crate::pipewire::pw_pod::SpaMetaType;
use crate::pipewire::pw_pod::SpaNodeCommand;
use crate::pipewire::pw_pod::SpaParamAvailability;
use crate::pipewire::pw_pod::SpaParamBitorder;
use crate::pipewire::pw_pod::SpaParamBuffers;
use crate::pipewire::pw_pod::SpaParamIo;
use crate::pipewire::pw_pod::SpaParamLatency;
use crate::pipewire::pw_pod::SpaParamMeta;
use crate::pipewire::pw_pod::SpaParamPortConfig;
use crate::pipewire::pw_pod::SpaParamPortConfigMode;
use crate::pipewire::pw_pod::SpaParamProcessLatency;
use crate::pipewire::pw_pod::SpaParamProfile;
use crate::pipewire::pw_pod::SpaParamRoute;
use crate::pipewire::pw_pod::SpaParamType;
use crate::pipewire::pw_pod::SpaProfiler;
use crate::pipewire::pw_pod::SpaProp;
use crate::pipewire::pw_pod::SpaPropInfo;
use crate::pipewire::pw_pod::SpaVideoChromaSite;
use crate::pipewire::pw_pod::SpaVideoColorMatrix;
use crate::pipewire::pw_pod::SpaVideoColorPrimaries;
use crate::pipewire::pw_pod::SpaVideoColorRange;
use crate::pipewire::pw_pod::SpaVideoFormat;
use crate::pipewire::pw_pod::SpaVideoInterlaceMode;
use crate::pipewire::pw_pod::SpaVideoMultiviewFlags;
use crate::pipewire::pw_pod::SpaVideoMultiviewMode;
use crate::pipewire::pw_pod::SpaVideoTransferFunction;
use crate::utils::errorfmt::ErrorFmt;
use std::fmt;
use std::fmt::Debug;
use std::fmt::DebugList;
use std::fmt::Formatter;
use std::fmt::Write;
trait PwPodObjectDebugger: Sync {
fn debug_property(&self, fmt: &mut Formatter<'_>, value: PwProp<'_>) -> fmt::Result;
fn id_name(&self, id: u32) -> Option<&'static str>;
}
struct PwPodObjectDebuggerSimple<F, G, H> {
key_name: F,
debug_pod: G,
id_name: H,
}
impl<F, G, H> PwPodObjectDebugger for PwPodObjectDebuggerSimple<F, G, H>
where
F: Fn(u32) -> Option<&'static str> + Sync,
G: Fn(u32, &mut Formatter<'_>, PwPod<'_>) -> fmt::Result + Sync,
H: Fn(u32) -> Option<&'static str> + Sync,
{
fn debug_property(&self, fmt: &mut Formatter<'_>, value: PwProp<'_>) -> fmt::Result {
let mut s = fmt.debug_struct("PwProp");
match (self.key_name)(value.key) {
Some(n) => s.field("key", &n),
_ => s.field("key", &value.key),
};
s.field("flags", &value.flags)
.field(
"pod",
&fmt::from_fn(|f| (self.debug_pod)(value.key, f, value.pod)),
)
.finish()
}
fn id_name(&self, id: u32) -> Option<&'static str> {
(self.id_name)(id)
}
}
fn choice_debug<F>(fmt: &mut Formatter<'_>, p: PwPod<'_>, ty: PwPodType, f: F) -> fmt::Result
where
F: Fn(&mut Formatter<'_>, PwPod<'_>) -> fmt::Result,
{
match p {
PwPod::Choice(c) if c.elements.ty == ty => fmt
.debug_struct("choice")
.field("ty", &c.ty)
.field("flags", &c.flags)
.field(
"elements",
&fmt::from_fn(|fmt| {
array_body_debug(fmt, c.elements, |l, p| {
match p.read_pod_body_packed(ty, c.elements.child_len) {
Ok(p) => {
l.entry(&fmt::from_fn(|fmt| f(fmt, p)));
true
}
Err(e) => {
let e = ErrorFmt(e);
l.entry(&fmt::from_fn(|fmt| {
write!(fmt, "Could not read choice element: {e}")
}));
false
}
}
})
}),
)
.finish(),
_ if p.ty() == ty => f(fmt, p),
_ => p.fmt(fmt),
}
}
fn id_debug<F>(fmt: &mut Formatter<'_>, p: PwPod<'_>, f: F) -> fmt::Result
where
F: Fn(&mut Formatter<'_>, u32) -> fmt::Result,
{
choice_debug(fmt, p, PW_TYPE_Id, |fmt, p| match p {
PwPod::Id(id) => f(fmt, id),
_ => p.fmt(fmt),
})
}
fn array_body_debug<F>(fmt: &mut Formatter<'_>, mut a: PwPodArray<'_>, f: F) -> fmt::Result
where
F: Fn(&mut DebugList<'_, '_>, &mut PwParser<'_>) -> bool,
{
let mut l = fmt.debug_list();
for _ in 0..a.n_elements {
if !f(&mut l, &mut a.elements) {
break;
}
}
l.finish()
}
fn array_debug<F>(fmt: &mut Formatter<'_>, p: PwPod<'_>, ty: PwPodType, f: F) -> fmt::Result
where
F: Fn(&mut DebugList<'_, '_>, &mut PwParser<'_>) -> bool,
{
match p {
PwPod::Array(a) if a.ty == ty => array_body_debug(fmt, a, f),
_ => p.fmt(fmt),
}
}
fn array_id_debug<F, T>(fmt: &mut Formatter<'_>, p: PwPod<'_>, f: F) -> fmt::Result
where
F: Fn(&mut DebugList<'_, '_>, u32) -> T,
{
array_debug(fmt, p, PW_TYPE_Id, |l, p| match p.read_id() {
Ok(a) => {
f(l, a);
true
}
Err(e) => {
let e = ErrorFmt(e);
l.entry(&fmt::from_fn(|f| write!(f, "Could not read id: {e}")));
false
}
})
}
fn object_id_name(id: u32) -> Option<&'static str> {
SpaParamType(id).name()
}
fn command_id_name(id: u32) -> Option<&'static str> {
SpaNodeCommand(id).name()
}
static PROP_INFO_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaPropInfo(key).name(),
debug_pod: |_, f: &mut Formatter<'_>, p: PwPod<'_>| p.fmt(f),
id_name: object_id_name,
};
static PROPS_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaProp(key).name(),
id_name: object_id_name,
debug_pod: |key, f: &mut Formatter<'_>, p: PwPod<'_>| match SpaProp(key) {
SPA_PROP_channelMap => array_id_debug(f, p, |l, a| {
l.entry(&SpaAudioChannel(a));
}),
SPA_PROP_iec958Codecs => array_id_debug(f, p, |l, a| {
l.entry(&SpaAudioIec958Codec(a));
}),
_ => p.fmt(f),
},
};
static FORMAT_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaFormat(key).name(),
id_name: object_id_name,
debug_pod: |key, f: &mut Formatter<'_>, p: PwPod<'_>| match SpaFormat(key) {
SPA_FORMAT_mediaType => id_debug(f, p, |f, a| SpaMediaType(a).fmt(f)),
SPA_FORMAT_mediaSubtype => id_debug(f, p, |f, a| SpaMediaSubtype(a).fmt(f)),
SPA_FORMAT_AUDIO_format => id_debug(f, p, |f, a| SpaAudioFormat(a).fmt(f)),
SPA_FORMAT_AUDIO_position => array_id_debug(f, p, |l, a| {
l.entry(&SpaAudioChannel(a));
}),
SPA_FORMAT_AUDIO_iec958Codec => id_debug(f, p, |f, a| SpaAudioIec958Codec(a).fmt(f)),
SPA_FORMAT_AUDIO_bitorder => id_debug(f, p, |f, a| SpaParamBitorder(a).fmt(f)),
SPA_FORMAT_VIDEO_format => id_debug(f, p, |f, a| SpaVideoFormat(a).fmt(f)),
SPA_FORMAT_VIDEO_interlaceMode => id_debug(f, p, |f, a| SpaVideoInterlaceMode(a).fmt(f)),
SPA_FORMAT_VIDEO_multiviewMode => id_debug(f, p, |f, a| SpaVideoMultiviewMode(a).fmt(f)),
SPA_FORMAT_VIDEO_multiviewFlags => id_debug(f, p, |f, a| SpaVideoMultiviewFlags(a).fmt(f)),
SPA_FORMAT_VIDEO_chromaSite => id_debug(f, p, |f, a| SpaVideoChromaSite(a).fmt(f)),
SPA_FORMAT_VIDEO_colorRange => id_debug(f, p, |f, a| SpaVideoColorRange(a).fmt(f)),
SPA_FORMAT_VIDEO_colorMatrix => id_debug(f, p, |f, a| SpaVideoColorMatrix(a).fmt(f)),
SPA_FORMAT_VIDEO_transferFunction => {
id_debug(f, p, |f, a| SpaVideoTransferFunction(a).fmt(f))
}
SPA_FORMAT_VIDEO_colorPrimaries => id_debug(f, p, |f, a| SpaVideoColorPrimaries(a).fmt(f)),
SPA_FORMAT_VIDEO_H264_streamFormat => id_debug(f, p, |f, a| SpaH264StreamFormat(a).fmt(f)),
SPA_FORMAT_VIDEO_H264_alignment => id_debug(f, p, |f, a| SpaH264Alignment(a).fmt(f)),
_ => p.fmt(f),
},
};
static PARAM_BUFFERS_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaParamBuffers(key).name(),
id_name: object_id_name,
debug_pod: |key, f: &mut Formatter<'_>, p: PwPod<'_>| match SpaParamBuffers(key) {
SPA_PARAM_BUFFERS_dataType => match p {
PwPod::Int(v) => SpaDataTypes(v as _).fmt(f),
_ => p.fmt(f),
},
_ => p.fmt(f),
},
};
static PARAM_META_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaParamMeta(key).name(),
id_name: object_id_name,
debug_pod: |key, f: &mut Formatter<'_>, p: PwPod<'_>| match SpaParamMeta(key) {
SPA_PARAM_META_type => id_debug(f, p, |f, b| SpaMetaType(b).fmt(f)),
_ => p.fmt(f),
},
};
static PARAM_IO_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaParamIo(key).name(),
id_name: object_id_name,
debug_pod: |key, f: &mut Formatter<'_>, p: PwPod<'_>| match SpaParamIo(key) {
SPA_PARAM_IO_id => id_debug(f, p, |f, b| SpaIoType(b).fmt(f)),
_ => p.fmt(f),
},
};
static PARAM_PROFILE_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaParamProfile(key).name(),
id_name: object_id_name,
debug_pod: |key, f: &mut Formatter<'_>, p: PwPod<'_>| match SpaParamProfile(key) {
SPA_PARAM_PROFILE_available => id_debug(f, p, |f, b| SpaParamAvailability(b).fmt(f)),
_ => p.fmt(f),
},
};
static PARAM_PORT_CONFIG_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaParamPortConfig(key).name(),
id_name: object_id_name,
debug_pod: |key, f: &mut Formatter<'_>, p: PwPod<'_>| match SpaParamPortConfig(key) {
SPA_PARAM_PORT_CONFIG_direction => id_debug(f, p, |f, b| SpaDirection(b).fmt(f)),
SPA_PARAM_PORT_CONFIG_mode => id_debug(f, p, |f, b| SpaParamPortConfigMode(b).fmt(f)),
_ => p.fmt(f),
},
};
static PARAM_ROUTE_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaParamRoute(key).name(),
id_name: object_id_name,
debug_pod: |key, f: &mut Formatter<'_>, p: PwPod<'_>| match SpaParamRoute(key) {
SPA_PARAM_ROUTE_direction => id_debug(f, p, |f, b| SpaDirection(b).fmt(f)),
SPA_PARAM_ROUTE_available => id_debug(f, p, |f, b| SpaParamAvailability(b).fmt(f)),
_ => p.fmt(f),
},
};
static PROFILER_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaProfiler(key).name(),
id_name: object_id_name,
debug_pod: |_, f: &mut Formatter<'_>, p: PwPod<'_>| p.fmt(f),
};
static PARAM_LATENCY_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaParamLatency(key).name(),
id_name: object_id_name,
debug_pod: |_, f: &mut Formatter<'_>, p: PwPod<'_>| p.fmt(f),
};
static PARAM_PROCESS_LATENCY_DEBUGGER: &'static dyn PwPodObjectDebugger =
&PwPodObjectDebuggerSimple {
key_name: |key| SpaParamProcessLatency(key).name(),
id_name: object_id_name,
debug_pod: |_, f: &mut Formatter<'_>, p: PwPod<'_>| p.fmt(f),
};
static COMMAND_NODE_DEBUGGER: &'static dyn PwPodObjectDebugger = &PwPodObjectDebuggerSimple {
key_name: |key| SpaNodeCommand(key).name(),
id_name: command_id_name,
debug_pod: |_, f: &mut Formatter<'_>, p: PwPod<'_>| p.fmt(f),
};
fn object_debugger(obj: PwPodObjectType) -> Option<&'static dyn PwPodObjectDebugger> {
let res: &dyn PwPodObjectDebugger = match obj {
PW_OBJECT_PropInfo => PROP_INFO_DEBUGGER,
PW_OBJECT_Props => PROPS_DEBUGGER,
PW_OBJECT_Format => FORMAT_DEBUGGER,
PW_OBJECT_ParamBuffers => PARAM_BUFFERS_DEBUGGER,
PW_OBJECT_ParamMeta => PARAM_META_DEBUGGER,
PW_OBJECT_ParamIO => PARAM_IO_DEBUGGER,
PW_OBJECT_ParamProfile => PARAM_PROFILE_DEBUGGER,
PW_OBJECT_ParamPortConfig => PARAM_PORT_CONFIG_DEBUGGER,
PW_OBJECT_ParamRoute => PARAM_ROUTE_DEBUGGER,
PW_OBJECT_Profiler => PROFILER_DEBUGGER,
PW_OBJECT_ParamLatency => PARAM_LATENCY_DEBUGGER,
PW_OBJECT_ParamProcessLatency => PARAM_PROCESS_LATENCY_DEBUGGER,
PW_COMMAND_Node => COMMAND_NODE_DEBUGGER,
_ => return None,
};
Some(res)
}
impl Debug for PwPodObject<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let debugger = object_debugger(self.ty);
let mut s = f.debug_struct("object");
s.field("type", &self.ty);
let name;
let mut id: &dyn Debug = &self.id;
if let Some(d) = debugger
&& let Some(n) = d.id_name(self.id)
{
name = n;
id = &name;
}
s.field("id", id);
s.field(
"props",
&fmt::from_fn(|f| {
let mut l = f.debug_list();
let mut parser = self.probs;
while parser.len() > 0 {
match parser.read_prop() {
Ok(p) => match debugger {
Some(d) => l.entry(&fmt::from_fn(|fmt| d.debug_property(fmt, p))),
_ => l.entry(&p),
},
Err(e) => {
let e = ErrorFmt(e);
l.entry(&fmt::from_fn(|f| {
write!(f, "Could not read object property: {e}")
}));
break;
}
};
}
l.finish()
}),
);
s.finish()
}
}
impl Debug for PwPodSequence<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut s = f.debug_struct("sequence");
s.field("unit", &self.unit);
s.field(
"controls",
&fmt::from_fn(|f| {
let mut l = f.debug_list();
let mut parser = self.controls;
while parser.len() > 0 {
match parser.read_control() {
Ok(c) => l.entry(&c),
Err(e) => {
let e = ErrorFmt(e);
l.entry(&fmt::from_fn(|f| {
write!(f, "Could not read control element: {e}")
}));
break;
}
};
}
l.finish()
}),
);
s.finish()
}
}
impl Debug for PwPodStruct<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut parser = self.fields;
let mut s = f.debug_struct("struct");
let mut field = String::new();
for i in 0.. {
if parser.len() == 0 {
break;
}
field.clear();
let _ = write!(&mut field, "\"{i}\"");
match parser.read_pod() {
Ok(p) => s.field(&field, &p),
Err(e) => {
let e = ErrorFmt(e);
s.field(
&field,
&fmt::from_fn(|f| write!(f, "Could not parse struct field: {e}")),
);
break;
}
};
}
s.finish()
}
}
impl Debug for PwPodArray<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
let mut parser = self.elements;
for _ in 0..self.n_elements {
match parser.read_pod_body_packed(self.ty, self.child_len) {
Ok(e) => list.entry(&e),
Err(e) => {
let e = ErrorFmt(e);
list.entry(&fmt::from_fn(|f| {
write!(f, "Could not parse array element: {e}")
}));
break;
}
};
}
list.finish()
}
}
impl Debug for PwPod<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
PwPod::None => write!(f, "None"),
PwPod::Bool(b) => write!(f, "{b}"),
PwPod::Id(id) => write!(f, "id({id})"),
PwPod::Int(i) => write!(f, "int({i})"),
PwPod::Long(l) => write!(f, "long({l})"),
PwPod::Float(v) => write!(f, "float({v})"),
PwPod::Double(d) => write!(f, "double({d})"),
PwPod::String(s) => write!(f, "string({s:?})"),
PwPod::Bytes(b) => write!(f, "bytes(len = {})", b.len()),
PwPod::Rectangle(r) => write!(f, "rectangle({}x{})", r.width, r.height),
PwPod::Fraction(v) => write!(f, "fraction({}/{})", v.num, v.denom),
PwPod::Bitmap(b) => write!(f, "bitmap(len = {})", b.len()),
PwPod::Array(a) => a.fmt(f),
PwPod::Struct(s) => s.fmt(f),
PwPod::Object(o) => o.fmt(f),
PwPod::Sequence(s) => s.fmt(f),
PwPod::Pointer(p) => p.fmt(f),
PwPod::Fd(v) => write!(f, "fd({v})"),
PwPod::Choice(c) => c.fmt(f),
}
}
}