1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use super::{
    unescape::{unescape, UnescapeError},
    GuidError,
};
use crate::{Unix, UnixType};
use std::convert::TryFrom;
use thiserror::Error;

use super::guid::decode_guid;

#[derive(Error, Debug, Clone)]
pub enum UnixError {
    #[error("Could not unescape: {0}")]
    UnescapeError(#[from] UnescapeError),
    #[error("GUID error: {0}")]
    GuidError(#[from] GuidError),
    #[error("Unknown key")]
    UnknownKey,
    #[error("Unknown runtime")]
    UnknownRuntime,
    #[error("Type is duplicate")]
    TypeDuplicate,
    #[error("Type is missing")]
    TypeMissing,
}

impl Unix {
    fn decode_type(type_str: &str, r#type: &mut Option<UnixType>) -> Result<(), UnixError> {
        if r#type.is_none() {
            *r#type = Some(UnixType::try_from(type_str)?);
            Ok(())
        } else {
            Err(UnixError::TypeDuplicate)
        }
    }
}

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

    fn try_from(server_address: &str) -> Result<Self, Self::Error> {
        let mut r#type = None;
        let mut guid = None;

        for key_value in server_address.split(',') {
            if let Some(guid_str) = key_value.strip_prefix("guid=") {
                decode_guid(guid_str, &mut guid)?;
            } else {
                Unix::decode_type(key_value, &mut r#type)?;
            }
        }

        if let Some(r#type) = r#type {
            Ok(Unix { r#type, guid })
        } else {
            Err(UnixError::TypeMissing)
        }
    }
}

impl UnixType {
    fn decode_path(path: &str) -> Result<UnixType, UnixError> {
        let path = UnixType::Path(unescape(path)?);
        Ok(path)
    }

    fn decode_dir(dir: &str) -> Result<UnixType, UnixError> {
        let dir = UnixType::Dir(unescape(dir)?);
        Ok(dir)
    }

    fn decode_tmpdir(tmpdir: &str) -> Result<UnixType, UnixError> {
        let tmpdir = UnixType::Tmpdir(unescape(tmpdir)?);
        Ok(tmpdir)
    }

    fn decode_abstract(abstract_: &str) -> Result<UnixType, UnixError> {
        let abstract_ = UnixType::Abstract(unescape(abstract_)?);
        Ok(abstract_)
    }

    fn decode_runtime(runtime: &str) -> Result<UnixType, UnixError> {
        let runtime = unescape(runtime)?;
        if &runtime == "yes" {
            Ok(UnixType::Runtime)
        } else {
            Err(UnixError::UnknownRuntime)
        }
    }
}

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

    fn try_from(server_address: &str) -> Result<Self, Self::Error> {
        if let Some(path) = server_address.strip_prefix("path=") {
            UnixType::decode_path(path)
        } else if let Some(dir) = server_address.strip_prefix("dir=") {
            UnixType::decode_dir(dir)
        } else if let Some(tmpdir) = server_address.strip_prefix("tmpdir=") {
            UnixType::decode_tmpdir(tmpdir)
        } else if let Some(abstract_) = server_address.strip_prefix("abstract=") {
            UnixType::decode_abstract(abstract_)
        } else if let Some(runtime) = server_address.strip_prefix("runtime=") {
            UnixType::decode_runtime(runtime)
        } else {
            Err(UnixError::UnknownKey)
        }
    }
}