Commit 9aed75d5 authored by AdminXVII's avatar AdminXVII
Browse files

Increase small heuristic to make the code more compact

parent a0cb1001
......@@ -46,7 +46,7 @@ fn get_git_rev() -> io::Result<String> {
String::from_utf8(out.stdout).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("git rev-parse master output was not UTF-8"),
"git rev-parse master output was not UTF-8",
)
})
})
......
......@@ -76,22 +76,17 @@ impl<'a> Iterator for MultipleBraceExpand<'a> {
fn next(&mut self) -> Option<Self::Item> {
if self.permutator.next_with_buffer(&mut self.buffer) {
let mut strings = self.buffer.iter();
let small_vec: SmallVec<[u8; 64]> =
self.tokens
.iter()
.fold(
SmallVec::with_capacity(64),
|mut small_vec, token| match *token {
BraceToken::Normal(ref text) => {
escape_string(&mut small_vec, text);
small_vec
}
BraceToken::Expander => {
escape_string(&mut small_vec, strings.next().unwrap());
small_vec
}
let small_vec =
self.tokens.iter().fold(SmallVec::with_capacity(64), |mut small_vec, token| {
escape_string(
&mut small_vec,
match *token {
BraceToken::Normal(ref text) => text,
BraceToken::Expander => strings.next().unwrap(),
},
);
small_vec
});
Some(unsafe { small::String::from_utf8_unchecked(small_vec.to_vec()) })
} else {
None
......@@ -117,45 +112,34 @@ where
fn next(&mut self) -> Option<Self::Item> {
match self.loop_count {
0 => {
let small_vec: SmallVec<[u8; 64]> =
self.tokens
.iter()
.fold(
SmallVec::with_capacity(64),
|mut small_vec, token| match *token {
BraceToken::Normal(ref text) => {
escape_string(&mut small_vec, text);
small_vec
}
BraceToken::Expander => {
escape_string(&mut small_vec, self.elements.next().unwrap());
small_vec
}
let small_vec =
self.tokens.iter().fold(SmallVec::with_capacity(64), |mut small_vec, token| {
escape_string(
&mut small_vec,
match *token {
BraceToken::Normal(ref text) => text,
BraceToken::Expander => self.elements.next().unwrap(),
},
);
small_vec
});
self.loop_count = 1;
Some(unsafe { small::String::from_utf8_unchecked(small_vec.to_vec()) })
}
_ => {
if let Some(element) = self.elements.next() {
let small_vec: SmallVec<[u8; 64]> = self.tokens.iter().fold(
SmallVec::with_capacity(64),
|mut small_vec, token| match *token {
BraceToken::Normal(ref text) => {
escape_string(&mut small_vec, text);
small_vec
}
BraceToken::Expander => {
escape_string(&mut small_vec, element);
small_vec
}
},
);
Some(unsafe { small::String::from_utf8_unchecked(small_vec.to_vec()) })
} else {
None
}
}
_ => self.elements.next().and_then(|element| {
let small_vec =
self.tokens.iter().fold(SmallVec::with_capacity(64), |mut small_vec, token| {
escape_string(
&mut small_vec,
match *token {
BraceToken::Normal(ref text) => text,
BraceToken::Expander => element,
},
);
small_vec
});
Some(unsafe { small::String::from_utf8_unchecked(small_vec.to_vec()) })
}),
}
}
}
......@@ -199,7 +183,7 @@ mod tests {
SingleBraceExpand {
elements: elements.iter().map(|element| *element),
tokens,
loop_count: 0,
loop_count: 0
}
.collect::<Vec<small::String>>(),
vec![
......
......@@ -8,20 +8,8 @@ macro_rules! string_function {
eprintln!("ion: {}: two arguments must be supplied", args[0]);
return 2;
}
3 => {
if args[1].$method(args[2].as_str()) {
0
} else {
1
}
}
_ => {
if args[2..].iter().any(|arg| args[1].$method(arg.as_str())) {
0
} else {
1
}
}
3 => !args[1].$method(args[2].as_str()) as i32,
_ => !args[2..].iter().any(|arg| args[1].$method(arg.as_str())) as i32,
}
}
};
......
......@@ -19,31 +19,30 @@ pub fn echo(args: &[small::String]) -> Result<(), io::Error> {
"--escape" => flags |= Flags::ESCAPE,
"--no-newline" => flags |= Flags::NO_NEWLINE,
"--no-spaces" => flags |= Flags::NO_SPACES,
_ => {
if arg.starts_with('-') {
let mut is_opts = true;
let opts = &arg[1..];
let mut short_flags = Flags::empty();
for argopt in opts.chars() {
match argopt {
'e' => short_flags |= Flags::ESCAPE,
'n' => short_flags |= Flags::NO_NEWLINE,
's' => short_flags |= Flags::NO_SPACES,
_ => {
is_opts = false;
break;
}
_ if arg.starts_with('-') => {
let mut is_opts = true;
let opts = &arg[1..];
let mut short_flags = Flags::empty();
for argopt in opts.chars() {
match argopt {
'e' => short_flags |= Flags::ESCAPE,
'n' => short_flags |= Flags::NO_NEWLINE,
's' => short_flags |= Flags::NO_SPACES,
_ => {
is_opts = false;
break;
}
}
if is_opts {
flags |= short_flags;
} else {
data.push(arg);
}
}
if is_opts {
flags |= short_flags;
} else {
data.push(arg);
}
}
_ => {
data.push(arg);
}
}
}
......
......@@ -33,10 +33,7 @@ pub fn random(args: &[small::String]) -> Result<(), small::String> {
writeln!(stdout, "{}", rand_num);
}
1 => {
writeln!(
stdout,
"Ion Shell does not currently support changing the seed"
);
writeln!(stdout, "Ion Shell does not currently support changing the seed");
}
2 => {
let arg1 = match args[0].parse::<u64>() {
......
......@@ -144,15 +144,13 @@ fn evaluate_arguments(arguments: &[small::String]) -> Result<bool, small::String
}
Some(arg) => {
// If there is no operator, check if the first argument is non-zero
arguments
.get(1)
.map_or(Ok(string_is_nonzero(arg)), |operator| {
// If there is no right hand argument, a condition was expected
let right_arg = arguments
.get(2)
.ok_or_else(|| small::String::from("parse error: condition expected"))?;
evaluate_expression(arg, operator, right_arg)
})
arguments.get(1).map_or(Ok(string_is_nonzero(arg)), |operator| {
// If there is no right hand argument, a condition was expected
let right_arg = arguments
.get(2)
.ok_or_else(|| small::String::from("parse error: condition expected"))?;
evaluate_expression(arg, operator, right_arg)
})
}
None => {
println!("{}", QUICK_GUIDE);
......@@ -189,7 +187,8 @@ fn files_have_same_device_and_inode_numbers(first: &str, second: &str) -> bool {
get_dev_and_inode(first).map_or(false, |left| {
// Obtain the device and inode of the second file or return FAILED
get_dev_and_inode(second).map_or(false, |right| {
// Compare the device and inodes of the first and second files
// Compare the device and inodes of the
// first and second files
left == right
})
})
......@@ -197,18 +196,19 @@ fn files_have_same_device_and_inode_numbers(first: &str, second: &str) -> bool {
/// Obtains the device and inode numbers of the file specified
fn get_dev_and_inode(filename: &str) -> Option<(u64, u64)> {
fs::metadata(filename)
.map(|file| (file.dev(), file.ino()))
.ok()
fs::metadata(filename).map(|file| (file.dev(), file.ino())).ok()
}
/// Exits SUCCESS if the first file is newer than the second file.
fn file_is_newer_than(first: &str, second: &str) -> bool {
// Obtain the modified file time of the first file or return FAILED
get_modified_file_time(first).map_or(false, |left| {
// Obtain the modified file time of the second file or return FAILED
// Obtain the modified file time of the second file or return
// FAILED
get_modified_file_time(second).map_or(false, |right| {
// If the first file is newer than the right file, return SUCCESS
// If the first file is newer
// than the right file,
// return SUCCESS
left > right
})
})
......@@ -216,9 +216,7 @@ fn file_is_newer_than(first: &str, second: &str) -> bool {
/// Obtain the time the file was last modified as a `SystemTime` type.
fn get_modified_file_time(filename: &str) -> Option<SystemTime> {
fs::metadata(filename)
.ok()
.and_then(|file| file.modified().ok())
fs::metadata(filename).ok().and_then(|file| file.modified().ok())
}
/// Attempt to parse a &str as a usize.
......@@ -272,9 +270,7 @@ fn match_flag_argument(flag: char, argument: &str) -> bool {
/// Exits SUCCESS if the file size is greather than zero.
fn file_size_is_greater_than_zero(filepath: &str) -> bool {
fs::metadata(filepath)
.ok()
.map_or(false, |metadata| metadata.len() > 0)
fs::metadata(filepath).ok().map_or(false, |metadata| metadata.len() > 0)
}
/// Exits SUCCESS if the file has read permissions. This function is rather low level because
......@@ -332,23 +328,17 @@ fn file_has_execute_permission(filepath: &str) -> bool {
/// Exits SUCCESS if the file argument is a socket
fn file_is_socket(filepath: &str) -> bool {
fs::metadata(filepath)
.ok()
.map_or(false, |metadata| metadata.file_type().is_socket())
fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_socket())
}
/// Exits SUCCESS if the file argument is a block device
fn file_is_block_device(filepath: &str) -> bool {
fs::metadata(filepath)
.ok()
.map_or(false, |metadata| metadata.file_type().is_block_device())
fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_block_device())
}
/// Exits SUCCESS if the file argument is a character device
fn file_is_character_device(filepath: &str) -> bool {
fs::metadata(filepath)
.ok()
.map_or(false, |metadata| metadata.file_type().is_char_device())
fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_char_device())
}
/// Exits SUCCESS if the file exists
......@@ -356,23 +346,17 @@ fn file_exists(filepath: &str) -> bool { Path::new(filepath).exists() }
/// Exits SUCCESS if the file is a regular file
fn file_is_regular(filepath: &str) -> bool {
fs::metadata(filepath)
.ok()
.map_or(false, |metadata| metadata.file_type().is_file())
fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_file())
}
/// Exits SUCCESS if the file is a directory
fn file_is_directory(filepath: &str) -> bool {
fs::metadata(filepath)
.ok()
.map_or(false, |metadata| metadata.file_type().is_dir())
fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_dir())
}
/// Exits SUCCESS if the file is a symbolic link
fn file_is_symlink(filepath: &str) -> bool {
fs::symlink_metadata(filepath)
.ok()
.map_or(false, |metadata| metadata.file_type().is_symlink())
fs::symlink_metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_symlink())
}
/// Exits SUCCESS if the string is not empty
......@@ -402,128 +386,44 @@ fn test_integers_arguments() {
args.iter().map(|s| (*s).into()).collect()
}
// Equal To
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-eq", "10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-eq", "5"])),
Ok(false)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-10", "-eq", "-10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-10", "-eq", "10"])),
Ok(false)
);
assert_eq!(evaluate_arguments(&vec_string(&["10", "-eq", "10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["10", "-eq", "5"])), Ok(false));
assert_eq!(evaluate_arguments(&vec_string(&["-10", "-eq", "-10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["-10", "-eq", "10"])), Ok(false));
// Greater Than or Equal To
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-ge", "10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-ge", "5"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["5", "-ge", "10"])),
Ok(false)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-9", "-ge", "-10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-10", "-ge", "-10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-10", "-ge", "10"])),
Ok(false)
);
assert_eq!(evaluate_arguments(&vec_string(&["10", "-ge", "10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["10", "-ge", "5"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["5", "-ge", "10"])), Ok(false));
assert_eq!(evaluate_arguments(&vec_string(&["-9", "-ge", "-10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["-10", "-ge", "-10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["-10", "-ge", "10"])), Ok(false));
// Less Than or Equal To
assert_eq!(
evaluate_arguments(&vec_string(&["5", "-le", "5"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["5", "-le", "10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-le", "5"])),
Ok(false)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-11", "-le", "-10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-10", "-le", "-10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-le", "-10"])),
Ok(false)
);
assert_eq!(evaluate_arguments(&vec_string(&["5", "-le", "5"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["5", "-le", "10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["10", "-le", "5"])), Ok(false));
assert_eq!(evaluate_arguments(&vec_string(&["-11", "-le", "-10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["-10", "-le", "-10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["10", "-le", "-10"])), Ok(false));
// Less Than
assert_eq!(
evaluate_arguments(&vec_string(&["5", "-lt", "10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-lt", "5"])),
Ok(false)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-11", "-lt", "-10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-lt", "-10"])),
Ok(false)
);
assert_eq!(evaluate_arguments(&vec_string(&["5", "-lt", "10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["10", "-lt", "5"])), Ok(false));
assert_eq!(evaluate_arguments(&vec_string(&["-11", "-lt", "-10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["10", "-lt", "-10"])), Ok(false));
// Greater Than
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-gt", "5"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["5", "-gt", "10"])),
Ok(false)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-9", "-gt", "-10"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-10", "-gt", "10"])),
Ok(false)
);
assert_eq!(evaluate_arguments(&vec_string(&["10", "-gt", "5"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["5", "-gt", "10"])), Ok(false));
assert_eq!(evaluate_arguments(&vec_string(&["-9", "-gt", "-10"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["-10", "-gt", "10"])), Ok(false));
// Not Equal To
assert_eq!(
evaluate_arguments(&vec_string(&["10", "-ne", "5"])),
Ok(true)
);
assert_eq!(
evaluate_arguments(&vec_string(&["5", "-ne", "5"])),
Ok(false)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-10", "-ne", "-10"])),
Ok(false)
);
assert_eq!(
evaluate_arguments(&vec_string(&["-10", "-ne", "10"])),
Ok(true)
);
assert_eq!(evaluate_arguments(&vec_string(&["10", "-ne", "5"])), Ok(true));
assert_eq!(evaluate_arguments(&vec_string(&["5", "-ne", "5"])), Ok(false));
assert_eq!(evaluate_arguments(&vec_string(&["-10", "-ne", "-10"])), Ok(false));
assert_eq!(evaluate_arguments(&vec_string(&["-10", "-ne", "10"])), Ok(true));
}
#[test]
......@@ -552,24 +452,12 @@ fn test_file_is_symlink() {
#[test]
fn test_file_has_execute_permission() {
assert_eq!(
file_has_execute_permission("../../testing/executable_file"),
true
);
assert_eq!(
file_has_execute_permission("../../testing/empty_file"),
false
);
assert_eq!(file_has_execute_permission("../../testing/executable_file"), true);
assert_eq!(file_has_execute_permission("../../testing/empty_file"), false);
}
#[test]
fn test_file_size_is_greater_than_zero() {
assert_eq!(
file_size_is_greater_than_zero("../../testing/file_with_text"),
true
);
assert_eq!(
file_size_is_greater_than_zero("../../testing/empty_file"),
false
);
assert_eq!(file_size_is_greater_than_zero("../../testing/file_with_text"), true);
assert_eq!(file_size_is_greater_than_zero("../../testing/empty_file"), false);
}
......@@ -24,11 +24,7 @@ pub struct ArgumentSplitter<'a> {
impl<'a> ArgumentSplitter<'a> {
pub fn new(data: &'a str) -> ArgumentSplitter<'a> {
ArgumentSplitter {
data,
read: 0,
bitflags: ArgumentFlags::empty(),
}
ArgumentSplitter { data, read: 0, bitflags: ArgumentFlags::empty() }
}
}
......@@ -72,16 +68,14 @@ impl<'a> Iterator for ArgumentSplitter<'a> {
// Disable COMM_1 and enable COMM_2 + ARRAY.
b'@' => {
self.bitflags.remove(ArgumentFlags::COMM_1);
self.bitflags
.insert(ArgumentFlags::COMM_2 | ArgumentFlags::ARRAY);
self.bitflags.insert(ArgumentFlags::COMM_2 | ArgumentFlags::ARRAY);
self.read += 1;
continue;
}
// Disable COMM_2 and enable COMM_1 + VARIAB.
b'$' => {
self.bitflags.remove(ArgumentFlags::COMM_2);
self.bitflags
.insert(ArgumentFlags::COMM_1 | ArgumentFlags::VARIAB);
self.bitflags.insert(ArgumentFlags::COMM_1 | ArgumentFlags::VARIAB);
self.read += 1;
continue;
}
......@@ -96,12 +90,8 @@ impl<'a> Iterator for ArgumentSplitter<'a> {
b'(' => {
// Disable VARIAB + ARRAY and enable METHOD.
// if variab or array are set
if self
.bitflags
.intersects(ArgumentFlags::VARIAB | ArgumentFlags::ARRAY)
{
self.bitflags
.remove(ArgumentFlags::VARIAB | ArgumentFlags::ARRAY);
if self.bitflags.intersects(ArgumentFlags::VARIAB | ArgumentFlags::ARRAY) {
self.bitflags.remove(ArgumentFlags::VARIAB | ArgumentFlags::ARRAY);
self.bitflags.insert(ArgumentFlags::METHOD);
}
level += 1
......@@ -125,9 +115,7 @@ impl<'a> Iterator for ArgumentSplitter<'a> {
}
// Break from the loop once a root-level space is found.
b' ' => {
if !self
.bitflags
.intersects(ArgumentFlags::DOUBLE | ArgumentFlags::METHOD)
if !self.bitflags.intersects(ArgumentFlags::DOUBLE | ArgumentFlags::METHOD)
&& level == 0
&& alevel == 0
&& blevel == 0
......@@ -140,8 +128,7 @@ impl<'a> Iterator for ArgumentSplitter<'a> {
self.read += 1;
// disable COMM_1 and COMM_2
self.bitflags
.remove(ArgumentFlags::COMM_1 | ArgumentFlags::COMM_2);
self.bitflags.remove(ArgumentFlags::COMM_1 | ArgumentFlags::COMM_2);
}
if start == self.read {
......@@ -181,22 +168,14 @@ mod tests {
#[test]
fn arrays() {
let input = "echo [ one two @[echo three four] five ] [ six seven ]";
let expected = vec![
"echo",
"[ one two @[echo three four] five ]",
"[ six seven ]",
];
let expected = vec!["echo", "[ one two @[echo three four] five ]", "[ six seven ]"];
compare(input, expected);
}