nextcloud-client-api 0.1.0

implementation of the socket API for the NextCloud client
Documentation
use core::fmt::{Display, Formatter, Result as FmtResult};

use thiserror::Error as ThisError;

use crate::api_verb::ApiVerb;

#[derive(Debug, PartialEq, Eq)]
pub struct MenuItem {
    verb: ApiVerb,
    description: String,
}

impl MenuItem {
    pub fn verb(&self) -> &ApiVerb {
        &self.verb
    }

    pub fn description(&self) -> &String {
        &self.description
    }
}

#[derive(Debug, ThisError)]
#[non_exhaustive]
pub enum Error {
    #[error("failed to parse menu item: {0}")]
    ParsingFailed(String),
}

impl TryFrom<&str> for MenuItem {
    type Error = Error;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        let parts = value.split(':').collect::<Vec<_>>();

        let Some((verb, description)) = parts.first().zip(parts.get(2)) else {
            return Err(Error::ParsingFailed(format!("invalid menu item: {value}")));
        };

        Ok(Self {
            verb: ApiVerb::try_from(*verb)
                .map_err(|err| Error::ParsingFailed(format!("invalid menu item: {err}")))?,
            description: (*description).to_owned(),
        })
    }
}

impl Display for MenuItem {
    #[expect(clippy::min_ident_chars, reason = "defined by trait")]
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        write!(f, "{}: {}", self.verb, self.description)
    }
}

#[cfg(test)]
#[expect(clippy::unwrap_used, reason = "in tests we panic")]
mod tests {
    use super::*;

    #[test]
    fn test_parsing() {
        let item = MenuItem::try_from("ACTIVITY::check activity").unwrap();
        let expected = MenuItem {
            verb: ApiVerb::Activity,
            description: "check activity".to_owned(),
        };

        assert_eq!(expected, item);
    }

    #[test]
    #[should_panic(expected = "invalid menu item: ACTIVITY:check activity")]
    fn test_missing_section() {
        let item = MenuItem::try_from("ACTIVITY:check activity").unwrap();
        let expected = MenuItem {
            verb: ApiVerb::Activity,
            description: "check activity".to_owned(),
        };

        assert_eq!(expected, item);
    }

    #[test]
    #[should_panic(expected = "invalid menu item: ACTIVITY_CHECK:check activity")]
    fn test_unknown_verb() {
        let item = MenuItem::try_from("ACTIVITY_CHECK:check activity").unwrap();
        let expected = MenuItem {
            verb: ApiVerb::Activity,
            description: "check activity".to_owned(),
        };

        assert_eq!(expected, item);
    }
}