Skip to main content

twilight_http/request/channel/thread/
create_thread.rs

1#[cfg(not(target_os = "wasi"))]
2use crate::response::{Response, ResponseFuture};
3use crate::{
4    client::Client,
5    error::Error,
6    request::{Request, TryIntoRequest},
7    routing::Route,
8};
9use serde::Serialize;
10use std::future::IntoFuture;
11use twilight_model::{
12    channel::{Channel, ChannelType, thread::AutoArchiveDuration},
13    id::{Id, marker::ChannelMarker},
14};
15use twilight_validate::channel::{
16    ChannelValidationError, is_thread as validate_is_thread, name as validate_name,
17};
18
19#[derive(Serialize)]
20struct CreateThreadFields<'a> {
21    #[serde(skip_serializing_if = "Option::is_none")]
22    auto_archive_duration: Option<AutoArchiveDuration>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    invitable: Option<bool>,
25    #[serde(rename = "type")]
26    kind: ChannelType,
27    name: &'a str,
28}
29
30/// Start a thread that is not connected to a message.
31///
32/// To make a [`PrivateThread`], the guild must also have the
33/// `PRIVATE_THREADS` feature.
34///
35/// [`PrivateThread`]: twilight_model::channel::ChannelType::PrivateThread
36#[must_use = "requests must be configured and executed"]
37pub struct CreateThread<'a> {
38    channel_id: Id<ChannelMarker>,
39    fields: Result<CreateThreadFields<'a>, ChannelValidationError>,
40    http: &'a Client,
41}
42
43impl<'a> CreateThread<'a> {
44    pub(crate) fn new(
45        http: &'a Client,
46        channel_id: Id<ChannelMarker>,
47        name: &'a str,
48        kind: ChannelType,
49    ) -> Self {
50        let fields = Ok(CreateThreadFields {
51            auto_archive_duration: None,
52            invitable: None,
53            kind,
54            name,
55        })
56        .and_then(|fields| {
57            validate_name(name)?;
58            validate_is_thread(kind)?;
59
60            Ok(fields)
61        });
62
63        Self {
64            channel_id,
65            fields,
66            http,
67        }
68    }
69
70    /// Set the thread's auto archive duration.
71    ///
72    /// Automatic archive durations are not locked behind the guild's boost
73    /// level.
74    pub const fn auto_archive_duration(
75        mut self,
76        auto_archive_duration: AutoArchiveDuration,
77    ) -> Self {
78        if let Ok(fields) = self.fields.as_mut() {
79            fields.auto_archive_duration = Some(auto_archive_duration);
80        }
81
82        self
83    }
84
85    /// Whether non-moderators can add other non-moderators to a thread.
86    pub const fn invitable(mut self, invitable: bool) -> Self {
87        if let Ok(fields) = self.fields.as_mut() {
88            fields.invitable = Some(invitable);
89        }
90
91        self
92    }
93}
94
95#[cfg(not(target_os = "wasi"))]
96impl IntoFuture for CreateThread<'_> {
97    type Output = Result<Response<Channel>, Error>;
98
99    type IntoFuture = ResponseFuture<Channel>;
100
101    fn into_future(self) -> Self::IntoFuture {
102        let http = self.http;
103
104        match self.try_into_request() {
105            Ok(request) => http.request(request),
106            Err(source) => ResponseFuture::error(source),
107        }
108    }
109}
110
111impl TryIntoRequest for CreateThread<'_> {
112    fn try_into_request(self) -> Result<Request, Error> {
113        let fields = self.fields.map_err(Error::validation)?;
114
115        Request::builder(&Route::CreateThread {
116            channel_id: self.channel_id.get(),
117        })
118        .json(&fields)
119        .build()
120    }
121}