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
//! Functions and data structures related to [Architecture]s.
use crate::Num;
use scotch_sys as s;
use std::io;
use std::mem;
use std::os::unix;
use std::path;
/// Equivalent of `SCOTCH_Arch`.
pub struct Architecture {
    pub(crate) inner: s::SCOTCH_Arch,
}
impl Architecture {
    /// Equivalent of `SCOTCH_archInit`.
    fn new() -> Architecture {
        let mut inner = mem::MaybeUninit::uninit();
        // SAFETY: inner should be initialized if SCOTCH_archInit returns zero.
        let inner = unsafe {
            if s::SCOTCH_archInit(inner.as_mut_ptr()) != 0 {
                panic!("Scotch internal error during architecture initialization");
            }
            inner.assume_init()
        };
        Architecture { inner }
    }
    /// Load an [`Architecture`] from the given file descriptor.
    ///
    /// This function closes the given file descriptor.
    ///
    /// # Safety
    ///
    /// The given file descriptor must be valid for reading and must not be a
    /// shared memory object.
    unsafe fn load(fd: unix::io::RawFd) -> io::Result<Architecture> {
        // SAFETY: caller must make sure the file descriptor is valid for reading.
        let file = unsafe { crate::fdopen(fd, "r\0")? };
        let mut architecture = Architecture::new();
        let inner = &mut architecture.inner as *mut s::SCOTCH_Arch;
        // SAFETY: file descriptor is valid and inner has been initialized.
        unsafe {
            if s::SCOTCH_archLoad(inner, file) != 0 {
                s::fclose(file);
                return Err(io::ErrorKind::Other.into());
            }
            s::fclose(file);
        }
        Ok(architecture)
    }
    /// Build an [`Architecture`] from the data found in standard input.
    ///
    /// This function closes standard input.
    ///
    /// Convenience wrapper around `SCOTCH_archLoad`.
    pub fn from_stdin() -> io::Result<Architecture> {
        // SAFETY: Standard input is open for reading and is not a shared memory object.
        unsafe { Architecture::load(0) }
    }
    /// Build an [`Architecture`] from the data found in the given file.
    ///
    /// Convenience wrapper around `SCOTCH_archLoad`.
    pub fn from_file(path: impl AsRef<path::Path>) -> io::Result<Architecture> {
        use std::fs;
        use unix::io::IntoRawFd as _;
        let file = fs::File::open(path)?;
        let fd = file.into_raw_fd();
        // SAFETY: file is open for reading and is not a shared memory object.
        unsafe { Architecture::load(fd) }
    }
    /// Equivalent of `SCOTCH_archCmplt`.
    pub fn complete(partnbr: Num) -> Architecture {
        let mut architecture = Architecture::new();
        let inner = &mut architecture.inner as *mut s::SCOTCH_Arch;
        // SAFETY: inner is initialized.
        unsafe {
            if s::SCOTCH_archCmplt(inner, partnbr) != 0 {
                panic!("Scotch internal error during architecture initialization");
            }
        }
        architecture
    }
}
impl Drop for Architecture {
    fn drop(&mut self) {
        unsafe {
            let inner = &mut self.inner as *mut s::SCOTCH_Arch;
            s::SCOTCH_archExit(inner);
        }
    }
}