Fix bitflag structs not being serialized as number

main
Dominik Nakamura 11 months ago
parent 62248b741c
commit d889caad8f
No known key found for this signature in database

@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- next-header -->
## [Unreleased] - ReleaseDate
### Fixed
- Some of the bitflag values like `FontFlags`, `Alignment` and `EventSubscription` were not always serialized as numbers but their string form, causing errors in the respective request or response.
## [0.11.1] - 2023-05-22
### Added

@ -22,6 +22,3 @@ version = "*"
skip = [
{ name = "regex-syntax", version = "=0.6.29" },
]
skip-tree = [
{ name = "windows-sys", version = "=0.45.0", depth = 3 },
]

@ -7,7 +7,7 @@ use crate::Error;
/// Monitoring type for audio outputs.
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize,
)]
#[non_exhaustive]
pub enum MonitorType {
@ -25,7 +25,10 @@ pub enum MonitorType {
bitflags! {
/// Different flags for font display that can be combined.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[derive(
Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize,
)]
#[serde(try_from = "u8", into = "u8")]
pub struct FontFlags: u8 {
/// Make the text appear thicker.
const BOLD = 1;
@ -62,7 +65,7 @@ bitflags! {
#[derive(
Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize,
)]
#[serde(transparent)]
#[serde(try_from = "u8", into = "u8")]
pub struct Alignment: u8 {
/// Align to the center.
const CENTER = 0;

@ -532,7 +532,6 @@ pub struct Font<'a> {
/// Font face.
pub face: &'a str,
/// Flags for different display styles.
#[serde(with = "crate::serde::bitflags_u8")]
pub flags: FontFlags,
/// Display size.
pub size: u32,

@ -136,7 +136,7 @@ bitflags! {
/// Bit flags for possible event subscriptions, that can be enabled when connecting to the OBS
/// instance.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(transparent)]
#[serde(into = "u32")]
pub struct EventSubscription: u32 {
/// Subscription value used to disable all events.
const NONE = 0;
@ -198,6 +198,12 @@ bitflags! {
}
}
impl From<EventSubscription> for u32 {
fn from(value: EventSubscription) -> Self {
value.bits()
}
}
#[allow(dead_code)]
#[derive(Serialize_repr)]
#[repr(i8)]

@ -267,6 +267,7 @@ impl QtWindowState {
/// │ bottom
/// │
/// Y
/// ```
#[derive(Clone, Copy, Debug, Default)]
pub struct QtRect {
/// Left or X/horizontal position of the rectangle.

@ -101,13 +101,13 @@ pub struct SceneItemTransform {
#[serde(rename = "height")]
pub height: f32,
/// The point on the source that the item is manipulated from.
#[serde(rename = "alignment", with = "crate::serde::bitflags_u8")]
#[serde(rename = "alignment")]
pub alignment: Alignment,
/// Type of bounding box.
#[serde(rename = "boundsType")]
pub bounds_type: BoundsType,
/// Alignment of the bounding box.
#[serde(rename = "boundsAlignment", with = "crate::serde::bitflags_u8")]
#[serde(rename = "boundsAlignment")]
pub bounds_alignment: Alignment,
/// Width of the bounding box.
#[serde(rename = "boundsWidth")]

@ -1,128 +0,0 @@
use std::{
fmt::{self, Display},
marker::PhantomData,
};
use serde::{
de::{self, Deserializer, Visitor},
ser::Serializer,
};
#[derive(Debug, thiserror::Error)]
enum Error {
#[error("value is too large for an u8: {0}")]
ValueTooLarge(#[source] std::num::TryFromIntError),
#[error("conversion from integer failed: {0}")]
IntConversionFailed(String),
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Into<u8> + Copy,
{
serializer.serialize_u8((*value).into())
}
pub fn deserialize<'de, D, T, TE>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: TryFrom<u8, Error = TE>,
TE: Display,
{
deserializer.deserialize_u8(BitflagsU8Visitor { flags: PhantomData })
}
struct BitflagsU8Visitor<T, TE> {
flags: PhantomData<(T, TE)>,
}
impl<'de, T, TE> Visitor<'de> for BitflagsU8Visitor<T, TE>
where
T: TryFrom<u8, Error = TE>,
TE: Display,
{
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("bitflags encoded as u8 integer")
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
u8::try_from(v)
.map_err(|e| de::Error::custom(Error::ValueTooLarge(e)))
.and_then(|v| self.visit_u8(v))
}
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: de::Error,
{
T::try_from(v).map_err(|e| de::Error::custom(Error::IntConversionFailed(e.to_string())))
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
u8::try_from(v)
.map_err(|e| de::Error::custom(Error::ValueTooLarge(e)))
.and_then(|v| self.visit_u8(v))
}
}
#[cfg(test)]
mod tests {
use bitflags::bitflags;
use serde::{Deserialize, Serialize};
use serde_test::{assert_tokens, Token};
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq)]
struct Flags: u8 {
const ONE = 1;
const TWO = 2;
}
}
impl From<Flags> for u8 {
fn from(value: Flags) -> Self {
value.bits()
}
}
impl TryFrom<u8> for Flags {
type Error = crate::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Self::from_bits(value).ok_or(Self::Error::UnknownFlags(value))
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct SimpleFlags {
#[serde(with = "super")]
value: Flags,
}
#[test]
fn roundtrip() {
assert_tokens(
&SimpleFlags {
value: Flags::ONE | Flags::TWO,
},
&[
Token::Struct {
name: "SimpleFlags",
len: 1,
},
Token::Str("value"),
Token::U8(3),
Token::StructEnd,
],
);
}
}

@ -1,5 +1,4 @@
pub mod audio_tracks;
pub mod bitflags_u8;
pub mod duration_millis;
pub mod duration_timecode;
pub mod json_string;

@ -0,0 +1,13 @@
use anyhow::Result;
use obws::requests::EventSubscription;
use crate::common;
#[tokio::test]
async fn client() -> Result<()> {
let client = common::new_client().await?;
client.reidentify(EventSubscription::ALL).await?;
Ok(())
}

@ -1,5 +1,6 @@
#![cfg(feature = "test-integration")]
mod client;
mod common;
mod config;
mod filters;

Loading…
Cancel
Save