Skip to content

add some more From impls + IntoCow #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@

## [Unreleased] - ReleaseDate

[Commits](https://github.com/twitch-rs/twitch_types/compare/v0.3.5...Unreleased)
[Commits](https://github.com/twitch-rs/twitch_types/compare/v0.3.6...Unreleased)

## [v0.3.6] - 2022-10-28

[Commits](https://github.com/twitch-rs/twitch_types/compare/v0.3.5...v0.3.6)

### Added

* Added `IntoCow` trait to easily take braids to be converted into `Cow`s

### Changed

* Added `impl From<&'a Owned> for &'a Ref` and `impl<'a> From<&'a Owned> for Cow<'a, Ref>` for all braids

## [v0.3.5] - 2022-10-22

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "twitch_types"
version = "0.3.5"
version = "0.3.6"
edition = "2021"
repository = "https://github.com/twitch-rs/twitch_types"
license = "MIT OR Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Twitch Types | Rust library for common types used in Twitch
============================================

[![github]](https://github.com/twitch-rs/twitch_types)&ensp;[![crates-io]](https://crates.io/crates/twitch_types)&ensp;[![docs-rs-big]](https://docs.rs/twitch_types/0.3.5/twitch_types)
[![github]](https://github.com/twitch-rs/twitch_types)&ensp;[![crates-io]](https://crates.io/crates/twitch_types)&ensp;[![docs-rs-big]](https://docs.rs/twitch_types/0.3.6/twitch_types)

[github]: https://img.shields.io/badge/github-twitch--rs/twitch__types-8da0cb?style=for-the-badge&labelColor=555555&logo=github
[crates-io]: https://img.shields.io/crates/v/twitch_types.svg?style=for-the-badge&color=fc8d62&logo=rust
Expand Down
2 changes: 1 addition & 1 deletion release.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
dev-version = false
pre-release-commit-message = "release {{crate_name}} {{version}}"
tag = false
push = false
publish = false
enable-features = ["all", "twitch_oauth2/all", "unsupported"]
consolidate-commits = false
pre-release-replacements = [
{file="CHANGELOG.md", search="Unreleased", replace="v{{version}}", prerelease=false},
{file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", prerelease=false},
Expand Down
6 changes: 6 additions & 0 deletions src/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@
#[aliri_braid::braid(serde)]
pub struct UserId;

impl_extra!(UserId, UserIdRef);

/// A users display name
#[aliri_braid::braid(serde)]
pub struct DisplayName;

impl_extra!(DisplayName, DisplayNameRef);

/// A nickname, not capitalized.
#[aliri_braid::braid(serde)]
pub struct Nickname;

impl_extra!(Nickname, NicknameRef);

/// A username, also specified as login. Should not be capitalized.
pub type UserName = Nickname;

Expand Down
2 changes: 2 additions & 0 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use serde::{Deserialize, Serialize};
#[aliri_braid::braid(serde)]
pub struct HexColor;

impl_extra!(HexColor, HexColorRef);

/// Colors a user can have
#[derive(Debug, PartialEq, Eq, Deserialize, Clone)]
#[serde(field_identifier, rename_all = "snake_case")]
Expand Down
8 changes: 8 additions & 0 deletions src/emote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ use serde::{Deserialize, Serialize};
#[aliri_braid::braid(serde)]
pub struct BadgeSetId;

impl_extra!(BadgeSetId, BadgeSetIdRef);

/// A channel chat badge ID
#[aliri_braid::braid(serde)]
pub struct ChatBadgeId;

impl_extra!(ChatBadgeId, ChatBadgeIdRef);

/// A chat Emote ID
#[aliri_braid::braid(serde)]
pub struct EmoteId;

impl_extra!(EmoteId, EmoteIdRef);

impl EmoteIdRef {
/// Generates url for this emote.
///
Expand Down Expand Up @@ -214,6 +220,8 @@ impl EmoteUrlBuilder<'_> {
#[aliri_braid::braid(serde)]
pub struct EmoteSetId;

impl_extra!(EmoteSetId, EmoteSetIdRef);

/// An emote index as defined by eventsub, similar to IRC `emotes` twitch tag.
#[derive(PartialEq, Eq, Deserialize, Serialize, Debug, Clone)]
#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
Expand Down
2 changes: 2 additions & 0 deletions src/eventsub.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// An EventSub Subscription ID
#[aliri_braid::braid(serde)]
pub struct EventSubId;

impl_extra!(EventSubId, EventSubIdRef);
2 changes: 2 additions & 0 deletions src/goal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use serde::{Deserialize, Serialize};
#[aliri_braid::braid(serde)]
pub struct CreatorGoalId;

impl_extra!(CreatorGoalId, CreatorGoalIdRef);

/// Type of creator goal
#[derive(PartialEq, Eq, Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
Expand Down
140 changes: 140 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,114 @@
#![cfg_attr(nightly, feature(doc_auto_cfg))]
//! Twitch types

macro_rules! impl_extra {
(validated, $owned:path, $ref:path, $error:path) => {
impl<'a> TryFrom<&'a String> for &'a $ref {
type Error = $error;
fn try_from(string: &'a String) -> Result<Self, $error> {
<$ref>::from_str(string.as_str())
}
}

impl_extra!(@all, $owned, $ref);
};
($owned:path, $ref:path) => {
impl<'a> From<&'a String> for &'a $ref {
fn from(string: &'a String) -> Self {
<$ref>::from_str(string.as_str())
}
}

impl_extra!(@all, $owned, $ref);
};
(@all, $owned:path, $ref:path) => {
impl $ref {
/// Get a
#[doc = concat!("[`Cow<'_, ", stringify!($ref), ">`](std::borrow::Cow::Borrowed)")]
pub fn as_cow<'a>(&'a self) -> ::std::borrow::Cow<'a, $ref> {
self.into()
}
}

impl<'a> From<&'a $owned> for &'a $ref {
fn from(owned: &'a $owned) -> Self {
&*owned
}
}

impl<'a> From<&'a $owned> for ::std::borrow::Cow<'a, $ref> {
fn from(owned: &'a $owned) -> Self {
::std::borrow::Cow::Borrowed(&*owned)
}
}

impl<'a> crate::IntoCow<'a, $ref> for &'a $ref {
fn to_cow(self) -> ::std::borrow::Cow<'a, $ref> {
::std::borrow::Cow::Borrowed(self)
}
}

impl<'a> crate::IntoCow<'a, $ref> for $owned {
fn to_cow(self) -> ::std::borrow::Cow<'a, $ref> {
::std::borrow::Cow::Owned(self)
}
}

impl<'a> crate::IntoCow<'a, $ref> for &'a $owned {
fn to_cow(self) -> ::std::borrow::Cow<'a, $ref> {
::std::borrow::Cow::Borrowed(self.as_ref())
}
}
};
}

/// Convert a type into a [`Cow`](std::borrow::Cow)
pub trait IntoCow<'a, Ref: ?Sized>
where Ref: ToOwned {
/// Make the cow with proper ownership, muu
fn to_cow(self) -> std::borrow::Cow<'a, Ref>
where &'a Self: 'a;
}

impl<'a, R> IntoCow<'a, R> for std::borrow::Cow<'a, R>
where
&'a R: Into<&'a R>,
R: ToOwned + ?Sized + 'a,
&'a R: Into<std::borrow::Cow<'a, R>>,
R::Owned: Into<std::borrow::Cow<'a, R>>,
{
fn to_cow(self) -> std::borrow::Cow<'a, R> {
match self {
std::borrow::Cow::Borrowed(b) => b.into(),
std::borrow::Cow::Owned(o) => o.into(),
}
}
}

impl<'a, R> IntoCow<'a, R> for &'a str
where
&'a str: Into<&'a R>,
R: ToOwned + ?Sized + 'a,
{
fn to_cow(self) -> std::borrow::Cow<'a, R> { std::borrow::Cow::Borrowed(self.into()) }
}

impl<'a, R> IntoCow<'a, R> for &'a String
where
&'a String: Into<&'a R>,
R: ToOwned + ?Sized + 'a,
{
fn to_cow(self) -> std::borrow::Cow<'a, R> { std::borrow::Cow::Borrowed(self.into()) }
}

impl<'a, R> IntoCow<'a, R> for String
where
String: Into<R::Owned>,
R: ToOwned + ?Sized + 'a,
{
fn to_cow(self) -> std::borrow::Cow<'a, R> { std::borrow::Cow::Owned(self.into()) }
}

mod basic;
// cc: https://github.com/rust-lang/rust/issues/83428, can't use glob imports and keep the modules private
#[cfg(feature = "color")]
Expand Down Expand Up @@ -54,3 +162,35 @@ pub use crate::stream::*;
pub use crate::time::*;
#[cfg(feature = "user")]
pub use crate::user::*;

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn lol() {
assert!(broadcaster_id("literal"));
assert!(!broadcaster_id(String::from("string")));
assert!(broadcaster_id(&String::from("ref string")));
assert!(broadcaster_id(UserIdRef::from_static("static ref")));
assert!(!broadcaster_id(UserId::new(String::from("owned"))));
assert!(broadcaster_id(&UserId::new(String::from("borrowed owned"))));
assert!(broadcaster_id(&*UserId::new(String::from("deref owned"))));
assert!(!broadcaster_id(std::borrow::Cow::Owned(UserId::new(
String::from("cow owned")
))));
assert!(broadcaster_id(std::borrow::Cow::Borrowed(
UserIdRef::from_static("cow borrowed")
)));
}
/// aa
pub fn broadcaster_id<'a>(broadcaster_id: impl IntoCow<'a, UserIdRef> + 'a) -> bool {
struct K<'a> {
id: std::borrow::Cow<'a, UserIdRef>,
}
let k = K {
id: broadcaster_id.to_cow(),
};
matches!(k.id, std::borrow::Cow::Borrowed(_))
}
Comment on lines +187 to +195
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nerixyz I think this solves the issue described in twitch-rs/twitch_api#280 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this should solve it 👍

}
4 changes: 4 additions & 0 deletions src/moderation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use serde::{Deserialize, Serialize};
#[aliri_braid::braid(serde)]
pub struct BlockedTermId;

impl_extra!(BlockedTermId, BlockedTermIdRef);

/// Status of a message that is or was in AutoMod queue
#[derive(PartialEq, Eq, Deserialize, Serialize, Debug, Clone)]
#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
Expand All @@ -23,3 +25,5 @@ pub enum AutomodStatus {
/// A message ID
#[aliri_braid::braid(serde)]
pub struct MsgId;

impl_extra!(MsgId, MsgIdRef);
12 changes: 12 additions & 0 deletions src/points.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,38 @@ use crate::{DisplayName, UserId, UserName};
#[aliri_braid::braid(serde)]
pub struct RewardId;

impl_extra!(RewardId, RewardIdRef);

/// A reward redemption ID.
#[aliri_braid::braid(serde)]
pub struct RedemptionId;

impl_extra!(RedemptionId, RedemptionIdRef);

/// A poll ID
#[aliri_braid::braid(serde)]
pub struct PollId;

impl_extra!(PollId, PollIdRef);

/// A poll choice ID
#[aliri_braid::braid(serde)]
pub struct PollChoiceId;

impl_extra!(PollChoiceId, PollChoiceIdRef);

/// A prediction ID
#[aliri_braid::braid(serde)]
pub struct PredictionId;

impl_extra!(PredictionId, PredictionIdRef);

/// A prediction choice ID
#[aliri_braid::braid(serde)]
pub struct PredictionOutcomeId;

impl_extra!(PredictionOutcomeId, PredictionOutcomeIdRef);

/// Reward redemption max
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
Expand Down
18 changes: 18 additions & 0 deletions src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,56 @@ use serde::{Deserialize, Serialize};
#[aliri_braid::braid(serde)]
pub struct StreamId;

impl_extra!(StreamId, StreamIdRef);

/// A game or category ID
#[aliri_braid::braid(serde)]
pub struct CategoryId;

impl_extra!(CategoryId, CategoryIdRef);

/// A tag ID
#[aliri_braid::braid(serde)]
pub struct TagId;

impl_extra!(TagId, TagIdRef);

/// A Team ID
#[aliri_braid::braid(serde)]
pub struct TeamId;

impl_extra!(TeamId, TeamIdRef);

/// A video ID
#[aliri_braid::braid(serde)]
pub struct VideoId;

impl_extra!(VideoId, VideoIdRef);

/// A clip ID
#[aliri_braid::braid(serde)]
pub struct ClipId;

impl_extra!(ClipId, ClipIdRef);

/// A Stream Segment ID.
#[aliri_braid::braid(serde)]
pub struct StreamSegmentId;

impl_extra!(StreamSegmentId, StreamSegmentIdRef);

/// A Hype Train ID
#[aliri_braid::braid(serde)]
pub struct HypeTrainId;

impl_extra!(HypeTrainId, HypeTrainIdRef);

/// A Charity Campaign ID
#[aliri_braid::braid(serde)]
pub struct CharityCampaignId;

impl_extra!(CharityCampaignId, CharityCampaignIdRef);

/// A game or category as defined by Twitch
#[derive(PartialEq, Eq, Deserialize, Serialize, Debug, Clone)]
#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
Expand Down
Loading