/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

Dia-Files

Copyright (C) 2019-2024  Anonymous

There are several releases over multiple years,
they are listed as ranges, such as: "2019-2024".

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/

#[cfg(unix)]
use {
    std::io::{Error, ErrorKind},
    crate::Result,
    super::super::{FilePermissions, Permissions, RawPermission},
};

#[cfg(test)]
mod tests;

#[cfg(unix)]
macro_rules! impl_from_file_permissions_for_raw_permission { ($($file_permissions: ty,)+) => {
    $(
        #[cfg(unix)]
        #[doc(cfg(unix))]
        impl From<$file_permissions> for RawPermission {

            fn from(file_permissions: $file_permissions) -> Self {
                ((file_permissions.user as RawPermission) << 6)
                    | ((file_permissions.group as RawPermission) << 3)
                    | (file_permissions.others as RawPermission)
            }

        }
    )+
}}

#[cfg(unix)]
impl_from_file_permissions_for_raw_permission! { &FilePermissions, FilePermissions, }

#[cfg(unix)]
#[doc(cfg(unix))]
impl TryFrom<RawPermission> for Permissions {

    type Error = Error;

    fn try_from(raw_permission: RawPermission) -> Result<Self> {
        if raw_permission == Permissions::None as RawPermission {
            Ok(Permissions::None)
        } else if raw_permission == Permissions::Read as RawPermission {
            Ok(Permissions::Read)
        } else if raw_permission == Permissions::Write as RawPermission {
            Ok(Permissions::Write)
        } else if raw_permission == Permissions::Execute as RawPermission {
            Ok(Permissions::Execute)
        } else if raw_permission == Permissions::ReadWrite as RawPermission {
            Ok(Permissions::ReadWrite)
        } else if raw_permission == Permissions::ReadExecute as RawPermission {
            Ok(Permissions::ReadExecute)
        } else if raw_permission == Permissions::WriteExecute as RawPermission {
            Ok(Permissions::WriteExecute)
        } else if raw_permission == Permissions::ReadWriteExecute as RawPermission {
            Ok(Permissions::ReadWriteExecute)
        } else {
            Err(Error::new(ErrorKind::Other, __!("Unknown permissions: {}", raw_permission)))
        }
    }

}

#[cfg(unix)]
#[doc(cfg(unix))]
impl TryFrom<&RawPermission> for Permissions {

    type Error = Error;

    fn try_from(raw_permission: &RawPermission) -> Result<Self> {
        Self::try_from(*raw_permission)
    }

}

#[cfg(unix)]
#[doc(cfg(unix))]
impl TryFrom<&RawPermission> for FilePermissions {

    type Error = Error;

    fn try_from(r: &RawPermission) -> Result<Self> {
        let r = *r;
        Ok(Self::new(
            Permissions::try_from(r >> 6)?,
            Permissions::try_from((r >> 3) & 0b_000_111)?,
            Permissions::try_from(r & 0b_000_000_111)?,
        ))
    }

}

#[cfg(unix)]
#[doc(cfg(unix))]
impl TryFrom<RawPermission> for FilePermissions {

    type Error = Error;

    fn try_from(r: RawPermission) -> Result<Self> {
        Self::try_from(&r)
    }

}
