use crate::client::{HttpMethod, Rerout};
use crate::error::Result;
use crate::models::{CreateTagInput, DeleteTagResult, ListTagsResult, Tag, UpdateTagInput};
#[derive(Debug, Clone)]
pub struct Tags<'a> {
client: &'a Rerout,
}
impl<'a> Tags<'a> {
pub(crate) fn new(client: &'a Rerout) -> Self {
Self { client }
}
pub async fn list(&self) -> Result<ListTagsResult> {
self.client
.request_json::<ListTagsResult, ()>(HttpMethod::Get, "/v1/projects/me/tags", None, None)
.await
}
pub async fn create(&self, input: &CreateTagInput) -> Result<Tag> {
self.client
.request_json::<Tag, _>(HttpMethod::Post, "/v1/projects/me/tags", None, Some(input))
.await
}
pub async fn update(&self, tag_id: &str, input: &UpdateTagInput) -> Result<Tag> {
let path = format!("/v1/projects/me/tags/{}", percent_encode_segment(tag_id));
self.client
.request_json::<Tag, _>(HttpMethod::Patch, &path, None, Some(input))
.await
}
pub async fn delete(&self, tag_id: &str) -> Result<DeleteTagResult> {
let path = format!("/v1/projects/me/tags/{}", percent_encode_segment(tag_id));
self.client
.request_json::<DeleteTagResult, ()>(HttpMethod::Delete, &path, None, None)
.await
}
}
fn percent_encode_segment(segment: &str) -> String {
let mut out = String::with_capacity(segment.len());
for byte in segment.bytes() {
if is_path_unreserved(byte) {
out.push(byte as char);
} else {
out.push('%');
out.push(hex_upper(byte >> 4));
out.push(hex_upper(byte & 0x0f));
}
}
out
}
#[inline]
fn is_path_unreserved(byte: u8) -> bool {
matches!(byte, b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~')
}
#[inline]
fn hex_upper(nibble: u8) -> char {
match nibble {
0..=9 => (b'0' + nibble) as char,
10..=15 => (b'A' + (nibble - 10)) as char,
_ => unreachable!("nibble out of range"),
}
}
#[cfg(test)]
mod tests {
use super::percent_encode_segment;
#[test]
fn encodes_plain_id_unchanged() {
assert_eq!(percent_encode_segment("tag_abc123"), "tag_abc123");
}
#[test]
fn encodes_slash() {
assert_eq!(percent_encode_segment("tag_a/b"), "tag_a%2Fb");
}
#[test]
fn encodes_spaces() {
assert_eq!(percent_encode_segment("tag a"), "tag%20a");
}
}