]> git.lizzy.rs Git - rust.git/blob - src/librustc_llvm/archive_ro.rs
b591e37f893e254d919441924b5176aefd6f935e
[rust.git] / src / librustc_llvm / archive_ro.rs
1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! A wrapper around LLVM's archive (.a) code
12
13 use ArchiveRef;
14
15 use std::ffi::CString;
16 use std::path::Path;
17 use std::slice;
18 use std::str;
19
20 pub struct ArchiveRO { ptr: ArchiveRef }
21
22 pub struct Iter<'a> {
23     archive: &'a ArchiveRO,
24     ptr: ::ArchiveIteratorRef,
25 }
26
27 pub struct Child<'a> {
28     name: Option<&'a str>,
29     data: &'a [u8],
30 }
31
32 impl ArchiveRO {
33     /// Opens a static archive for read-only purposes. This is more optimized
34     /// than the `open` method because it uses LLVM's internal `Archive` class
35     /// rather than shelling out to `ar` for everything.
36     ///
37     /// If this archive is used with a mutable method, then an error will be
38     /// raised.
39     pub fn open(dst: &Path) -> Option<ArchiveRO> {
40         return unsafe {
41             let s = path2cstr(dst);
42             let ar = ::LLVMRustOpenArchive(s.as_ptr());
43             if ar.is_null() {
44                 None
45             } else {
46                 Some(ArchiveRO { ptr: ar })
47             }
48         };
49
50         #[cfg(unix)]
51         fn path2cstr(p: &Path) -> CString {
52             use std::os::unix::prelude::*;
53             use std::ffi::OsStr;
54             let p: &OsStr = p.as_ref();
55             CString::new(p.as_bytes()).unwrap()
56         }
57         #[cfg(windows)]
58         fn path2cstr(p: &Path) -> CString {
59             CString::new(p.to_str().unwrap()).unwrap()
60         }
61     }
62
63     pub fn iter(&self) -> Iter {
64         unsafe {
65             Iter { ptr: ::LLVMRustArchiveIteratorNew(self.ptr), archive: self }
66         }
67     }
68 }
69
70 impl Drop for ArchiveRO {
71     fn drop(&mut self) {
72         unsafe {
73             ::LLVMRustDestroyArchive(self.ptr);
74         }
75     }
76 }
77
78 impl<'a> Iterator for Iter<'a> {
79     type Item = Child<'a>;
80
81     fn next(&mut self) -> Option<Child<'a>> {
82         unsafe {
83             let ptr = ::LLVMRustArchiveIteratorCurrent(self.ptr);
84             if ptr.is_null() {
85                 return None
86             }
87             let mut name_len = 0;
88             let name_ptr = ::LLVMRustArchiveChildName(ptr, &mut name_len);
89             let mut data_len = 0;
90             let data_ptr = ::LLVMRustArchiveChildData(ptr, &mut data_len);
91             let child = Child {
92                 name: if name_ptr.is_null() {
93                     None
94                 } else {
95                     let name = slice::from_raw_parts(name_ptr as *const u8,
96                                                      name_len as usize);
97                     str::from_utf8(name).ok().map(|s| s.trim())
98                 },
99                 data: slice::from_raw_parts(data_ptr as *const u8,
100                                             data_len as usize),
101             };
102             ::LLVMRustArchiveIteratorNext(self.ptr);
103             Some(child)
104         }
105     }
106 }
107
108 impl<'a> Drop for Iter<'a> {
109     fn drop(&mut self) {
110         unsafe {
111             ::LLVMRustArchiveIteratorFree(self.ptr);
112         }
113     }
114 }
115
116 impl<'a> Child<'a> {
117     pub fn name(&self) -> Option<&'a str> { self.name }
118     pub fn data(&self) -> &'a [u8] { self.data }
119 }