Skip to content

Commit cf6857b

Browse files
committed
auto merge of #13897 : aturon/rust/issue-6085, r=bjz
The `std::bitflags::bitflags!` macro did not provide support for adding attributes to the generates structure, due to limitations in the parser for macros. This patch works around the parser limitations by requiring a `flags` keyword in the `bitflags!` invocations: bitflags!( #[deriving(Hash)] #[doc="Three flags"] flags Flags: u32 { FlagA = 0x00000001, FlagB = 0x00000010, FlagC = 0x00000100 } ) The intent of `std::bitflags` is to allow building type-safe wrappers around C-style flags APIs. But in addition to construction these flags from the Rust side, we need a way to convert them from the C side. This patch adds a `from_bits` function, which is unsafe since the bits in question may not represent a valid combination of flags. Finally, this patch changes `std::io::FilePermissions` from an exposed `u32` representation to a typesafe representation (that only allows valid flag combinations) using the `std::bitflags`. Closes #6085.
2 parents 1f6db7f + 8d1d7d9 commit cf6857b

File tree

7 files changed

+101
-69
lines changed

7 files changed

+101
-69
lines changed

src/libnative/io/file_unix.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess)
335335

336336
pub fn mkdir(p: &CString, mode: io::FilePermission) -> IoResult<()> {
337337
super::mkerr_libc(retry(|| unsafe {
338-
libc::mkdir(p.with_ref(|p| p), mode as libc::mode_t)
338+
libc::mkdir(p.with_ref(|p| p), mode.bits() as libc::mode_t)
339339
}))
340340
}
341341

@@ -392,7 +392,7 @@ pub fn rename(old: &CString, new: &CString) -> IoResult<()> {
392392

393393
pub fn chmod(p: &CString, mode: io::FilePermission) -> IoResult<()> {
394394
super::mkerr_libc(retry(|| unsafe {
395-
libc::chmod(p.with_ref(|p| p), mode as libc::mode_t)
395+
libc::chmod(p.with_ref(|p| p), mode.bits() as libc::mode_t)
396396
}))
397397
}
398398

@@ -470,7 +470,9 @@ fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat {
470470
path: Path::new(path),
471471
size: stat.st_size as u64,
472472
kind: kind,
473-
perm: (stat.st_mode) as io::FilePermission & io::AllPermissions,
473+
perm: unsafe {
474+
io::FilePermission::from_bits(stat.st_mode as u32) & io::AllPermissions
475+
},
474476
created: mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64),
475477
modified: mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64),
476478
accessed: mktime(stat.st_atime as u64, stat.st_atime_nsec as u64),

src/libnative/io/file_win32.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ pub fn rename(old: &CString, new: &CString) -> IoResult<()> {
392392

393393
pub fn chmod(p: &CString, mode: io::FilePermission) -> IoResult<()> {
394394
super::mkerr_libc(as_utf16_p(p.as_str().unwrap(), |p| unsafe {
395-
libc::wchmod(p, mode as libc::c_int)
395+
libc::wchmod(p, mode.bits() as libc::c_int)
396396
}))
397397
}
398398

@@ -471,7 +471,9 @@ fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat {
471471
path: Path::new(path),
472472
size: stat.st_size as u64,
473473
kind: kind,
474-
perm: (stat.st_mode) as io::FilePermission & io::AllPermissions,
474+
perm: unsafe {
475+
io::FilePermission::from_bits(stat.st_mode as u32) & io::AllPermissions
476+
},
475477
created: stat.st_ctime as u64,
476478
modified: stat.st_mtime as u64,
477479
accessed: stat.st_atime as u64,

src/librustuv/file.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,9 @@ impl FsRequest {
283283
path: path,
284284
size: stat.st_size as u64,
285285
kind: kind,
286-
perm: (stat.st_mode as io::FilePermission) & io::AllPermissions,
286+
perm: unsafe {
287+
io::FilePermission::from_bits(stat.st_mode as u32) & io::AllPermissions
288+
},
287289
created: to_msec(stat.st_birthtim),
288290
modified: to_msec(stat.st_mtim),
289291
accessed: to_msec(stat.st_atim),

src/librustuv/uvio.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ impl IoFactory for UvIoFactory {
224224
}
225225
fn fs_mkdir(&mut self, path: &CString,
226226
perm: io::FilePermission) -> Result<(), IoError> {
227-
let r = FsRequest::mkdir(&self.loop_, path, perm as c_int);
227+
let r = FsRequest::mkdir(&self.loop_, path, perm.bits() as c_int);
228228
r.map_err(uv_error_to_io_error)
229229
}
230230
fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError> {
@@ -237,7 +237,7 @@ impl IoFactory for UvIoFactory {
237237
}
238238
fn fs_chmod(&mut self, path: &CString,
239239
perm: io::FilePermission) -> Result<(), IoError> {
240-
let r = FsRequest::chmod(&self.loop_, path, perm as c_int);
240+
let r = FsRequest::chmod(&self.loop_, path, perm.bits() as c_int);
241241
r.map_err(uv_error_to_io_error)
242242
}
243243
fn fs_readdir(&mut self, path: &CString, flags: c_int)

src/libstd/bitflags.rs

+46-25
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717
//! # Example
1818
//!
1919
//! ~~~rust
20-
//! bitflags!(Flags: u32 {
21-
//! FlagA = 0x00000001,
22-
//! FlagB = 0x00000010,
23-
//! FlagC = 0x00000100,
24-
//! FlagABC = FlagA.bits
25-
//! | FlagB.bits
26-
//! | FlagC.bits
27-
//! })
20+
//! bitflags!(
21+
//! flags Flags: u32 {
22+
//! static FlagA = 0x00000001,
23+
//! static FlagB = 0x00000010,
24+
//! static FlagC = 0x00000100,
25+
//! static FlagABC = FlagA.bits
26+
//! | FlagB.bits
27+
//! | FlagC.bits
28+
//! }
29+
//! )
2830
//!
2931
//! fn main() {
3032
//! let e1 = FlagA | FlagC;
@@ -40,10 +42,12 @@
4042
//! ~~~rust
4143
//! use std::fmt;
4244
//!
43-
//! bitflags!(Flags: u32 {
44-
//! FlagA = 0x00000001,
45-
//! FlagB = 0x00000010
46-
//! })
45+
//! bitflags!(
46+
//! flags Flags: u32 {
47+
//! static FlagA = 0x00000001,
48+
//! static FlagB = 0x00000010
49+
//! }
50+
//! )
4751
//!
4852
//! impl Flags {
4953
//! pub fn clear(&mut self) {
@@ -66,10 +70,16 @@
6670
//! }
6771
//! ~~~
6872
//!
73+
//! # Attributes
74+
//!
75+
//! Attributes can be attached to the generated `struct` by placing them
76+
//! before the `flags` keyword.
77+
//!
6978
//! # Derived traits
7079
//!
71-
//! The `Eq`, `TotalEq`, and `Clone` traits are automatically derived for the
72-
//! `struct` using the `deriving` attribute.
80+
//! The `Eq` and `Clone` traits are automatically derived for the `struct` using
81+
//! the `deriving` attribute. Additional traits can be derived by providing an
82+
//! explicit `deriving` attribute on `flags`.
7383
//!
7484
//! # Operators
7585
//!
@@ -91,17 +101,20 @@
91101
//! - `insert`: inserts the specified flags in-place
92102
//! - `remove`: removes the specified flags in-place
93103
104+
#![macro_escape]
105+
94106
#[macro_export]
95107
macro_rules! bitflags(
96-
($BitFlags:ident: $T:ty {
97-
$($Flag:ident = $value:expr),+
108+
($(#[$attr:meta])* flags $BitFlags:ident: $T:ty {
109+
$($(#[$Flag_attr:meta])* static $Flag:ident = $value:expr),+
98110
}) => (
99111
#[deriving(Eq, TotalEq, Clone)]
112+
$(#[$attr])*
100113
pub struct $BitFlags {
101114
bits: $T,
102115
}
103116

104-
$(pub static $Flag: $BitFlags = $BitFlags { bits: $value };)+
117+
$($(#[$Flag_attr])* pub static $Flag: $BitFlags = $BitFlags { bits: $value };)+
105118

106119
impl $BitFlags {
107120
/// Returns an empty set of flags.
@@ -114,6 +127,12 @@ macro_rules! bitflags(
114127
self.bits
115128
}
116129

130+
/// Convert from underlying bit representation. Unsafe because the
131+
/// bits are not guaranteed to represent valid flags.
132+
pub unsafe fn from_bits(bits: $T) -> $BitFlags {
133+
$BitFlags { bits: bits }
134+
}
135+
117136
/// Returns `true` if no flags are currently stored.
118137
pub fn is_empty(&self) -> bool {
119138
*self == $BitFlags::empty()
@@ -170,14 +189,16 @@ macro_rules! bitflags(
170189
mod tests {
171190
use ops::{BitOr, BitAnd, Sub};
172191

173-
bitflags!(Flags: u32 {
174-
FlagA = 0x00000001,
175-
FlagB = 0x00000010,
176-
FlagC = 0x00000100,
177-
FlagABC = FlagA.bits
178-
| FlagB.bits
179-
| FlagC.bits
180-
})
192+
bitflags!(
193+
flags Flags: u32 {
194+
static FlagA = 0x00000001,
195+
static FlagB = 0x00000010,
196+
static FlagC = 0x00000100,
197+
static FlagABC = FlagA.bits
198+
| FlagB.bits
199+
| FlagC.bits
200+
}
201+
)
181202

182203
#[test]
183204
fn test_bits(){

src/libstd/io/fs.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1119,7 +1119,7 @@ mod test {
11191119
check!(File::create(&input));
11201120
check!(chmod(&input, io::UserRead));
11211121
check!(copy(&input, &out));
1122-
assert!(check!(out.stat()).perm & io::UserWrite == 0);
1122+
assert!(!check!(out.stat()).perm.intersects(io::UserWrite));
11231123

11241124
check!(chmod(&input, io::UserFile));
11251125
check!(chmod(&out, io::UserFile));
@@ -1193,9 +1193,9 @@ mod test {
11931193
let file = tmpdir.join("in.txt");
11941194

11951195
check!(File::create(&file));
1196-
assert!(check!(stat(&file)).perm & io::UserWrite == io::UserWrite);
1196+
assert!(check!(stat(&file)).perm.contains(io::UserWrite));
11971197
check!(chmod(&file, io::UserRead));
1198-
assert!(check!(stat(&file)).perm & io::UserWrite == 0);
1198+
assert!(!check!(stat(&file)).perm.contains(io::UserWrite));
11991199

12001200
match chmod(&tmpdir.join("foo"), io::UserRWX) {
12011201
Ok(..) => fail!("wanted a failure"),

src/libstd/io/mod.rs

+38-33
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ use fmt;
224224
use int;
225225
use iter::Iterator;
226226
use libc;
227+
use ops::{BitOr, BitAnd, Sub};
227228
use os;
228229
use option::{Option, Some, None};
229230
use path::Path;
@@ -1558,36 +1559,40 @@ pub struct UnstableFileStat {
15581559
pub gen: u64,
15591560
}
15601561

1561-
/// A set of permissions for a file or directory is represented by a set of
1562-
/// flags which are or'd together.
1563-
pub type FilePermission = u32;
1564-
1565-
// Each permission bit
1566-
pub static UserRead: FilePermission = 0x100;
1567-
pub static UserWrite: FilePermission = 0x080;
1568-
pub static UserExecute: FilePermission = 0x040;
1569-
pub static GroupRead: FilePermission = 0x020;
1570-
pub static GroupWrite: FilePermission = 0x010;
1571-
pub static GroupExecute: FilePermission = 0x008;
1572-
pub static OtherRead: FilePermission = 0x004;
1573-
pub static OtherWrite: FilePermission = 0x002;
1574-
pub static OtherExecute: FilePermission = 0x001;
1575-
1576-
// Common combinations of these bits
1577-
pub static UserRWX: FilePermission = UserRead | UserWrite | UserExecute;
1578-
pub static GroupRWX: FilePermission = GroupRead | GroupWrite | GroupExecute;
1579-
pub static OtherRWX: FilePermission = OtherRead | OtherWrite | OtherExecute;
1580-
1581-
/// A set of permissions for user owned files, this is equivalent to 0644 on
1582-
/// unix-like systems.
1583-
pub static UserFile: FilePermission = UserRead | UserWrite | GroupRead | OtherRead;
1584-
/// A set of permissions for user owned directories, this is equivalent to 0755
1585-
/// on unix-like systems.
1586-
pub static UserDir: FilePermission = UserRWX | GroupRead | GroupExecute |
1587-
OtherRead | OtherExecute;
1588-
/// A set of permissions for user owned executables, this is equivalent to 0755
1589-
/// on unix-like systems.
1590-
pub static UserExec: FilePermission = UserDir;
1591-
1592-
/// A mask for all possible permission bits
1593-
pub static AllPermissions: FilePermission = 0x1ff;
1562+
bitflags!(
1563+
#[doc="A set of permissions for a file or directory is represented
1564+
by a set of flags which are or'd together."]
1565+
#[deriving(Hash)]
1566+
#[deriving(Show)]
1567+
flags FilePermission: u32 {
1568+
static UserRead = 0o400,
1569+
static UserWrite = 0o200,
1570+
static UserExecute = 0o100,
1571+
static GroupRead = 0o040,
1572+
static GroupWrite = 0o020,
1573+
static GroupExecute = 0o010,
1574+
static OtherRead = 0o004,
1575+
static OtherWrite = 0o002,
1576+
static OtherExecute = 0o001,
1577+
1578+
static UserRWX = UserRead.bits | UserWrite.bits | UserExecute.bits,
1579+
static GroupRWX = GroupRead.bits | GroupWrite.bits | GroupExecute.bits,
1580+
static OtherRWX = OtherRead.bits | OtherWrite.bits | OtherExecute.bits,
1581+
1582+
#[doc="Permissions for user owned files, equivalent to 0644 on
1583+
unix-like systems."]
1584+
static UserFile = UserRead.bits | UserWrite.bits | GroupRead.bits | OtherRead.bits,
1585+
1586+
#[doc="Permissions for user owned directories, equivalent to 0755 on
1587+
unix-like systems."]
1588+
static UserDir = UserRWX.bits | GroupRead.bits | GroupExecute.bits |
1589+
OtherRead.bits | OtherExecute.bits,
1590+
1591+
#[doc="Permissions for user owned executables, equivalent to 0755
1592+
on unix-like systems."]
1593+
static UserExec = UserDir.bits,
1594+
1595+
#[doc="All possible permissions enabled."]
1596+
static AllPermissions = UserRWX.bits | GroupRWX.bits | OtherRWX.bits
1597+
}
1598+
)

0 commit comments

Comments
 (0)