mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 06:25:10 +01:00
Add dedicated Rgb
struct to replace [u8; 3]
This commit is contained in:
parent
7b2de9ad39
commit
181b30304f
13 changed files with 164 additions and 88 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -235,6 +235,12 @@ version = "3.16.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
|
@ -1668,6 +1674,15 @@ dependencies = [
|
|||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f86ae463694029097b846d8f99fd5536740602ae00022c0c50c5600720b2f71"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.8"
|
||||
|
@ -2302,6 +2317,7 @@ dependencies = [
|
|||
"pretty_env_logger",
|
||||
"rc-box",
|
||||
"reqwest",
|
||||
"rgb",
|
||||
"ron",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -2791,7 +2807,7 @@ version = "0.1.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -49,6 +49,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- MSRV (Minimal Supported Rust Version) was bumped from `1.70.0` to `1.80.0`
|
||||
- Some dependencies was bumped: `reqwest` to `0.12.7` and `ron` to `0.8.1`
|
||||
- `tokio` version was explicitly specified as `1.39` and feature `io-util` was enabled for it
|
||||
- `[u8; 3]` sometimes used for RGB values was replaced with dedicated `Rgb` struct: ([#1151][pr1151])
|
||||
- `serde_rgb` module from `types.rs` file was removed
|
||||
- `CreateForumTopic`, `ForumTopicCreated` and `ForumTopic` structs now use `Rgb` instead of `[u8; 3]` for `icon_color` field
|
||||
- Added `rgb` crate dependency to Cargo.toml
|
||||
- Added `Rgb` struct with `From` implementation for `RGB8` type from popular `rgb` crate
|
||||
|
||||
- Support for TBA 7.2 ([#1146](pr1146))
|
||||
- Remove `flags` field from `StickerSet` struct
|
||||
|
@ -60,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[pr1134]: https://github.com/teloxide/teloxide/pull/1134
|
||||
[pr1146]: https://github.com/teloxide/teloxide/pull/1146
|
||||
[pr1147]: https://github.com/teloxide/teloxide/pull/1147
|
||||
[pr1151]: https://github.com/teloxide/teloxide/pull/1151
|
||||
|
||||
### Removed
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ rc-box = "1.1.1"
|
|||
chrono = { version = "0.4.32", default-features = false }
|
||||
either = "1.6.1"
|
||||
bitflags = { version = "1.2" }
|
||||
rgb = "0.8.48"
|
||||
|
||||
vecrem = { version = "0.1", optional = true }
|
||||
|
||||
|
|
|
@ -2754,9 +2754,11 @@ Schema(
|
|||
),
|
||||
Param(
|
||||
name: "icon_color",
|
||||
// FIXME: use an Rgb or something
|
||||
ty: u32,
|
||||
descr: Doc(md: "Color of the topic icon in RGB format. Currently, must be one of 7322096 (0x6FB9F0), 16766590 (0xFFD67E), 13338331 (0xCB86DB), 9367192 (0x8EEE98), 16749490 (0xFF93B2), or 16478047 (0xFB6F5F)")
|
||||
ty: RawTy("Rgb"),
|
||||
descr: Doc(
|
||||
md: "Color of the topic icon in RGB format. Currently, must be one of 7322096 (`0x6FB9F0`), 16766590 (`0xFFD67E`), 13338331 (`0xCB86DB`), 9367192 (`0x8EEE98`), 16749490 (`0xFF93B2`), or 16478047 (`0xFB6F5F`). To construct color from these values use [`Rgb::from_u32`]",
|
||||
md_links: {"`Rgb::from_u32`": "crate::types::Rgb::from_u32"}
|
||||
)
|
||||
),
|
||||
Param(
|
||||
name: "icon_custom_emoji_id",
|
||||
|
|
|
@ -671,7 +671,7 @@ trait ErasableRequester<'a> {
|
|||
&self,
|
||||
chat_id: Recipient,
|
||||
name: String,
|
||||
icon_color: u32,
|
||||
icon_color: Rgb,
|
||||
icon_custom_emoji_id: String,
|
||||
) -> ErasedRequest<'a, CreateForumTopic, Self::Err>;
|
||||
|
||||
|
@ -1506,7 +1506,7 @@ where
|
|||
&self,
|
||||
chat_id: Recipient,
|
||||
name: String,
|
||||
icon_color: u32,
|
||||
icon_color: Rgb,
|
||||
icon_custom_emoji_id: String,
|
||||
) -> ErasedRequest<'a, CreateForumTopic, Self::Err> {
|
||||
Requester::create_forum_topic(self, chat_id, name, icon_color, icon_custom_emoji_id).erase()
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
requests::{JsonRequest, MultipartRequest},
|
||||
types::{
|
||||
BotCommand, BusinessConnectionId, ChatId, ChatPermissions, InlineQueryResult, InputFile,
|
||||
InputMedia, InputSticker, LabeledPrice, MessageId, Recipient, StickerFormat, ThreadId,
|
||||
InputMedia, InputSticker, LabeledPrice, MessageId, Recipient, Rgb, StickerFormat, ThreadId,
|
||||
UserId,
|
||||
},
|
||||
Bot,
|
||||
|
@ -686,7 +686,7 @@ impl Requester for Bot {
|
|||
&self,
|
||||
chat_id: C,
|
||||
name: N,
|
||||
icon_color: u32,
|
||||
icon_color: Rgb,
|
||||
icon_custom_emoji_id: I,
|
||||
) -> Self::CreateForumTopic
|
||||
where
|
||||
|
|
|
@ -949,11 +949,11 @@ macro_rules! requester_forward {
|
|||
(@method create_forum_topic $body:ident $ty:ident) => {
|
||||
type CreateForumTopic = $ty![CreateForumTopic];
|
||||
|
||||
fn create_forum_topic<C, N, I>(&self, chat_id: C, name: N, icon_color: u32, icon_custom_emoji_id: I) -> Self::CreateForumTopic where C: Into<Recipient>,
|
||||
fn create_forum_topic<C, N, I>(&self, chat_id: C, name: N, icon_color: Rgb, icon_custom_emoji_id: I) -> Self::CreateForumTopic where C: Into<Recipient>,
|
||||
N: Into<String>,
|
||||
I: Into<String> {
|
||||
let this = self;
|
||||
$body!(create_forum_topic this (chat_id: C, name: N, icon_color: u32, icon_custom_emoji_id: I))
|
||||
$body!(create_forum_topic this (chat_id: C, name: N, icon_color: Rgb, icon_custom_emoji_id: I))
|
||||
}
|
||||
};
|
||||
(@method edit_forum_topic $body:ident $ty:ident) => {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::types::{ForumTopic, Recipient};
|
||||
use crate::types::{ForumTopic, Recipient, Rgb};
|
||||
|
||||
impl_payload! {
|
||||
/// Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\_manage\_topics_ administrator rights. Returns information about the created topic as a `ForumTopic` object.
|
||||
|
@ -13,8 +13,10 @@ impl_payload! {
|
|||
pub chat_id: Recipient [into],
|
||||
/// Topic name, 1-128 characters
|
||||
pub name: String [into],
|
||||
/// Color of the topic icon in RGB format. Currently, must be one of 7322096 (0x6FB9F0), 16766590 (0xFFD67E), 13338331 (0xCB86DB), 9367192 (0x8EEE98), 16749490 (0xFF93B2), or 16478047 (0xFB6F5F)
|
||||
pub icon_color: u32,
|
||||
/// Color of the topic icon in RGB format. Currently, must be one of 7322096 (`0x6FB9F0`), 16766590 (`0xFFD67E`), 13338331 (`0xCB86DB`), 9367192 (`0x8EEE98`), 16749490 (`0xFF93B2`), or 16478047 (`0xFB6F5F`). To construct color from these values use [`Rgb::from_u32`]
|
||||
///
|
||||
/// [`Rgb::from_u32`]: crate::types::Rgb::from_u32
|
||||
pub icon_color: Rgb,
|
||||
/// Unique identifier of the custom emoji shown as the topic icon. Use `getForumTopicIconStickers` to get all allowed custom emoji identifiers.
|
||||
pub icon_custom_emoji_id: String [into],
|
||||
}
|
||||
|
|
|
@ -702,7 +702,7 @@ pub trait Requester {
|
|||
&self,
|
||||
chat_id: C,
|
||||
name: N,
|
||||
icon_color: u32,
|
||||
icon_color: Rgb,
|
||||
icon_custom_emoji_id: I,
|
||||
) -> Self::CreateForumTopic
|
||||
where
|
||||
|
|
|
@ -128,6 +128,7 @@ pub use reply_markup::*;
|
|||
pub use reply_parameters::*;
|
||||
pub use request_id::*;
|
||||
pub use response_parameters::*;
|
||||
pub use rgb::*;
|
||||
pub use sent_web_app_message::*;
|
||||
pub use shared_user::*;
|
||||
pub use shipping_address::*;
|
||||
|
@ -262,6 +263,7 @@ mod reply_markup;
|
|||
mod reply_parameters;
|
||||
mod request_id;
|
||||
mod response_parameters;
|
||||
mod rgb;
|
||||
mod sent_web_app_message;
|
||||
mod shared_user;
|
||||
mod shipping_address;
|
||||
|
@ -544,67 +546,3 @@ pub(crate) mod option_msg_id_as_int {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod serde_rgb {
|
||||
use serde::{de::Visitor, Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S: Serializer>(&this: &[u8; 3], s: S) -> Result<S::Ok, S::Error> {
|
||||
s.serialize_u32(to_u32(this))
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<[u8; 3], D::Error> {
|
||||
struct V;
|
||||
|
||||
impl Visitor<'_> for V {
|
||||
type Value = [u8; 3];
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("an integer represeting an RGB color")
|
||||
}
|
||||
|
||||
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(from_u32(v))
|
||||
}
|
||||
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
self.visit_u32(v.try_into().map_err(|_| E::custom("rgb value doesn't fit u32"))?)
|
||||
}
|
||||
}
|
||||
d.deserialize_u32(V)
|
||||
}
|
||||
|
||||
fn to_u32([r, g, b]: [u8; 3]) -> u32 {
|
||||
u32::from_be_bytes([0, r, g, b])
|
||||
}
|
||||
|
||||
fn from_u32(rgb: u32) -> [u8; 3] {
|
||||
let [_, r, g, b] = rgb.to_be_bytes();
|
||||
[r, g, b]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes() {
|
||||
assert_eq!(to_u32([0xAA, 0xBB, 0xCC]), 0x00AABBCC);
|
||||
assert_eq!(from_u32(0x00AABBCC), [0xAA, 0xBB, 0xCC]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json() {
|
||||
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
struct Struct {
|
||||
#[serde(with = "self")]
|
||||
color: [u8; 3],
|
||||
}
|
||||
|
||||
let json = format!(r#"{{"color":{}}}"#, 0x00AABBCC);
|
||||
let Struct { color } = serde_json::from_str(&json).unwrap();
|
||||
|
||||
assert_eq!(color, [0xAA, 0xBB, 0xCC])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::types::ThreadId;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{Rgb, ThreadId};
|
||||
|
||||
/// This object represents a forum topic.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#forumtopiccreated).
|
||||
|
@ -16,9 +16,7 @@ pub struct ForumTopic {
|
|||
pub name: String,
|
||||
|
||||
/// Color of the topic icon in RGB format.
|
||||
// FIXME: use/add a specialized rgb color type?
|
||||
#[serde(with = "crate::types::serde_rgb")]
|
||||
pub icon_color: [u8; 3],
|
||||
pub icon_color: Rgb,
|
||||
|
||||
/// Unique identifier of the custom emoji shown as the topic icon.
|
||||
// FIXME: CustomEmojiId
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::Rgb;
|
||||
|
||||
/// This object represents a service message about a new forum topic created in
|
||||
/// the chat.
|
||||
///
|
||||
|
@ -11,9 +13,7 @@ pub struct ForumTopicCreated {
|
|||
pub name: String,
|
||||
|
||||
/// Color of the topic icon in RGB format.
|
||||
// FIXME: use/add a specialized rgb color type?
|
||||
#[serde(with = "crate::types::serde_rgb")]
|
||||
pub icon_color: [u8; 3],
|
||||
pub icon_color: Rgb,
|
||||
|
||||
/// Unique identifier of the custom emoji shown as the topic icon.
|
||||
// FIXME: CustomEmojiId
|
||||
|
@ -22,7 +22,7 @@ pub struct ForumTopicCreated {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::types::ForumTopicCreated;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn deserialization() {
|
||||
|
@ -32,7 +32,7 @@ mod tests {
|
|||
let event = serde_json::from_str::<ForumTopicCreated>(json).unwrap();
|
||||
|
||||
assert_eq!(event.name, "???");
|
||||
assert_eq!(event.icon_color, [0x8E, 0xEE, 0x98]);
|
||||
assert_eq!(event.icon_color, Rgb { r: 0x8E, g: 0xEE, b: 0x98 });
|
||||
assert_eq!(event.icon_custom_emoji_id.as_deref(), Some("5312536423851630001"));
|
||||
}
|
||||
}
|
||||
|
|
113
crates/teloxide-core/src/types/rgb.rs
Normal file
113
crates/teloxide-core/src/types/rgb.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use rgb::RGB8;
|
||||
use serde::{de::Visitor, Deserialize, Serialize};
|
||||
|
||||
/// RGB color format
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Rgb {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl Rgb {
|
||||
/// Convert a [`Rgb`] struct into a big endian `u32` representing the RGB
|
||||
/// color.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use teloxide_core::types::Rgb;
|
||||
/// assert_eq!(Rgb { r: 0xAA, g: 0xBB, b: 0xCC }.to_u32(), 0xAABBCC);
|
||||
/// ```
|
||||
///
|
||||
/// [`Rgb`]: Rgb
|
||||
pub fn to_u32(self) -> u32 {
|
||||
u32::from_be_bytes([0, self.r, self.g, self.b])
|
||||
}
|
||||
|
||||
/// Convert a big endian `u32` representing the RGB color into a [`Rgb`]
|
||||
/// struct.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use teloxide_core::types::Rgb;
|
||||
/// assert_eq!(Rgb::from_u32(0xAABBCC), Rgb { r: 0xAA, g: 0xBB, b: 0xCC });
|
||||
/// ```
|
||||
///
|
||||
/// [`Rgb`]: Rgb
|
||||
pub fn from_u32(rgb: u32) -> Self {
|
||||
let [_, r, g, b] = rgb.to_be_bytes();
|
||||
Rgb { r, g, b }
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Rgb {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_u32(self.to_u32())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Rgb {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct V;
|
||||
|
||||
impl Visitor<'_> for V {
|
||||
type Value = Rgb;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("an integer represeting an RGB color")
|
||||
}
|
||||
|
||||
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(Self::Value::from_u32(v))
|
||||
}
|
||||
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
self.visit_u32(v.try_into().map_err(|_| E::custom("rgb value doesn't fit u32"))?)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_u32(V)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RGB8> for Rgb {
|
||||
fn from(color: RGB8) -> Self {
|
||||
Rgb { r: color.r, g: color.g, b: color.b }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn json() {
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Struct {
|
||||
color: Rgb,
|
||||
}
|
||||
|
||||
let json = format!(r#"{{"color":{}}}"#, 0x00AABBCC);
|
||||
let Struct { color } = serde_json::from_str(&json).unwrap();
|
||||
|
||||
assert_eq!(color, Rgb { r: 0xAA, g: 0xBB, b: 0xCC })
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue