Skip to main content

use_tar/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4//! Tar entry labels and typeflag mappings for `RustUse`.
5
6use core::fmt;
7
8/// Common tar file extension.
9pub const TAR_EXTENSION: &str = "tar";
10/// Common gzip-compressed tar extension.
11pub const TAR_GZIP_EXTENSION: &str = "tar.gz";
12/// Common xz-compressed tar extension.
13pub const TAR_XZ_EXTENSION: &str = "tar.xz";
14/// Common zstd-compressed tar extension.
15pub const TAR_ZSTD_EXTENSION: &str = "tar.zst";
16
17/// Tar entry type labels.
18#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
19pub enum TarEntryType {
20    /// Regular file entry.
21    #[default]
22    Regular,
23    /// Directory entry.
24    Directory,
25    /// Symbolic link entry.
26    Symlink,
27    /// Hard link entry.
28    Hardlink,
29    /// Block device entry.
30    BlockDevice,
31    /// Character device entry.
32    CharacterDevice,
33    /// FIFO entry.
34    Fifo,
35    /// Global extended header entry.
36    GlobalExtendedHeader,
37    /// Extended header entry.
38    ExtendedHeader,
39    /// Unknown or unsupported tar entry type.
40    Unknown,
41}
42
43impl TarEntryType {
44    /// Returns a stable lowercase label.
45    #[must_use]
46    pub const fn as_str(self) -> &'static str {
47        match self {
48            Self::Regular => "regular",
49            Self::Directory => "directory",
50            Self::Symlink => "symlink",
51            Self::Hardlink => "hardlink",
52            Self::BlockDevice => "block-device",
53            Self::CharacterDevice => "character-device",
54            Self::Fifo => "fifo",
55            Self::GlobalExtendedHeader => "global-extended-header",
56            Self::ExtendedHeader => "extended-header",
57            Self::Unknown => "unknown",
58        }
59    }
60
61    /// Maps a raw tar typeflag byte to a label.
62    #[must_use]
63    pub const fn from_typeflag(typeflag: u8) -> Self {
64        match typeflag {
65            0 | b'0' => Self::Regular,
66            b'1' => Self::Hardlink,
67            b'2' => Self::Symlink,
68            b'3' => Self::CharacterDevice,
69            b'4' => Self::BlockDevice,
70            b'5' => Self::Directory,
71            b'6' => Self::Fifo,
72            b'g' => Self::GlobalExtendedHeader,
73            b'x' => Self::ExtendedHeader,
74            _ => Self::Unknown,
75        }
76    }
77
78    /// Returns the standard tar typeflag byte when one is available.
79    #[must_use]
80    pub const fn typeflag(self) -> Option<u8> {
81        match self {
82            Self::Regular => Some(b'0'),
83            Self::Hardlink => Some(b'1'),
84            Self::Symlink => Some(b'2'),
85            Self::CharacterDevice => Some(b'3'),
86            Self::BlockDevice => Some(b'4'),
87            Self::Directory => Some(b'5'),
88            Self::Fifo => Some(b'6'),
89            Self::GlobalExtendedHeader => Some(b'g'),
90            Self::ExtendedHeader => Some(b'x'),
91            Self::Unknown => None,
92        }
93    }
94}
95
96impl fmt::Display for TarEntryType {
97    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
98        formatter.write_str(self.as_str())
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::{TAR_EXTENSION, TAR_GZIP_EXTENSION, TarEntryType};
105
106    #[test]
107    fn maps_tar_typeflags() {
108        assert_eq!(TarEntryType::from_typeflag(b'5'), TarEntryType::Directory);
109        assert_eq!(TarEntryType::from_typeflag(b'2'), TarEntryType::Symlink);
110        assert_eq!(TarEntryType::Regular.typeflag(), Some(b'0'));
111        assert_eq!(TarEntryType::Unknown.typeflag(), None);
112    }
113
114    #[test]
115    fn exposes_tar_extension_labels() {
116        assert_eq!(TAR_EXTENSION, "tar");
117        assert_eq!(TAR_GZIP_EXTENSION, "tar.gz");
118    }
119}