Skip to content

Commit

Permalink
Also lift list_all_objects. Now the native/web IO stuff has a smaller…
Browse files Browse the repository at this point in the history
… surface area, making it easier to add more web support for #21.
  • Loading branch information
dabreegster committed Oct 5, 2020
1 parent e536525 commit 5706226
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 103 deletions.
5 changes: 5 additions & 0 deletions abstutil/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,8 @@ pub fn load_all_objects<T: DeserializeOwned>(dir: String) -> Vec<(String, T)> {
}
tree.into_iter().collect()
}

// Just list all things from a directory, return sorted by name, with file extension removed.
pub fn list_all_objects(dir: String) -> Vec<String> {
list_dir(dir).into_iter().map(|x| basename(&x)).collect()
}
117 changes: 46 additions & 71 deletions abstutil/src/io_native.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
// Normal file IO using the filesystem

pub use crate::io::*;
use crate::time::{clear_current_line, prettyprint_time};
use crate::{elapsed_seconds, prettyprint_usize, to_json, Timer, PROGRESS_FREQUENCY_SECONDS};
use instant::Instant;
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::collections::BTreeSet;
use std::fs::File;
use std::io::{stdout, BufReader, BufWriter, Error, ErrorKind, Read, Write};
use std::path::Path;

// TODO Idea: Have a wrapper type DotJSON(...) and DotBin(...) to distinguish raw path strings
fn maybe_write_json<T: Serialize>(path: &str, obj: &T) -> Result<(), Error> {
if !path.ends_with(".json") {
panic!("write_json needs {} to end with .json", path);
}
std::fs::create_dir_all(std::path::Path::new(path).parent().unwrap())
.expect("Creating parent dir failed");

let mut file = File::create(path)?;
file.write_all(to_json(obj).as_bytes())?;
Ok(())
pub fn file_exists<I: Into<String>>(path: I) -> bool {
Path::new(&path.into()).exists()
}

pub fn write_json<T: Serialize>(path: String, obj: &T) {
if let Err(err) = maybe_write_json(&path, obj) {
panic!("Can't write_json({}): {}", path, err);
}
println!("Wrote {}", path);
// Returns full paths
pub fn list_dir(path: String) -> Vec<String> {
let mut files: Vec<String> = Vec::new();
match std::fs::read_dir(&path) {
Ok(iter) => {
for entry in iter {
files.push(entry.unwrap().path().to_str().unwrap().to_string());
}
}
Err(ref e) if e.kind() == ErrorKind::NotFound => {}
Err(e) => panic!("Couldn't read_dir {:?}: {}", path, e),
};
files.sort();
files
}

pub fn slurp_file(path: &str) -> Result<Vec<u8>, Error> {
Expand All @@ -47,6 +48,26 @@ pub fn maybe_read_binary<T: DeserializeOwned>(path: String, timer: &mut Timer) -
Ok(obj)
}

// TODO Idea: Have a wrapper type DotJSON(...) and DotBin(...) to distinguish raw path strings
fn maybe_write_json<T: Serialize>(path: &str, obj: &T) -> Result<(), Error> {
if !path.ends_with(".json") {
panic!("write_json needs {} to end with .json", path);
}
std::fs::create_dir_all(std::path::Path::new(path).parent().unwrap())
.expect("Creating parent dir failed");

let mut file = File::create(path)?;
file.write_all(to_json(obj).as_bytes())?;
Ok(())
}

pub fn write_json<T: Serialize>(path: String, obj: &T) {
if let Err(err) = maybe_write_json(&path, obj) {
panic!("Can't write_json({}): {}", path, err);
}
println!("Wrote {}", path);
}

fn maybe_write_binary<T: Serialize>(path: &str, obj: &T) -> Result<(), Error> {
if !path.ends_with(".bin") {
panic!("write_binary needs {} to end with .bin", path);
Expand All @@ -66,30 +87,14 @@ pub fn write_binary<T: Serialize>(path: String, obj: &T) {
println!("Wrote {}", path);
}

// Just list all things from a directory, return sorted by name, with file extension removed.
pub fn list_all_objects(dir: String) -> Vec<String> {
let mut results: BTreeSet<String> = BTreeSet::new();
match std::fs::read_dir(dir) {
Ok(iter) => {
for entry in iter {
let filename = entry.unwrap().file_name();
let path = Path::new(&filename);
if path.to_string_lossy().starts_with('.') {
continue;
}
let name = path
.file_stem()
.unwrap()
.to_os_string()
.into_string()
.unwrap();
results.insert(name);
}
}
Err(ref e) if e.kind() == ErrorKind::NotFound => {}
Err(e) => panic!(e),
};
results.into_iter().collect()
// Idempotent
pub fn delete_file<I: Into<String>>(path: I) {
let path = path.into();
if std::fs::remove_file(&path).is_ok() {
println!("Deleted {}", path);
} else {
println!("{} doesn't exist, so not deleting it", path);
}
}

// TODO I'd like to get rid of this and just use Timer.read_file, but external libraries consume
Expand Down Expand Up @@ -177,33 +182,3 @@ impl Read for FileWithProgress {
Ok(bytes)
}
}

// Returns full paths
pub fn list_dir(path: String) -> Vec<String> {
let mut files: Vec<String> = Vec::new();
match std::fs::read_dir(&path) {
Ok(iter) => {
for entry in iter {
files.push(entry.unwrap().path().to_str().unwrap().to_string());
}
}
Err(ref e) if e.kind() == ErrorKind::NotFound => {}
Err(e) => panic!("Couldn't read_dir {:?}: {}", path, e),
};
files.sort();
files
}

pub fn file_exists<I: Into<String>>(path: I) -> bool {
Path::new(&path.into()).exists()
}

// Idempotent
pub fn delete_file<I: Into<String>>(path: I) {
let path = path.into();
if std::fs::remove_file(&path).is_ok() {
println!("Deleted {}", path);
} else {
println!("{} doesn't exist, so not deleting it", path);
}
}
55 changes: 23 additions & 32 deletions abstutil/src/io_web.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Since the local filesystem can't be read from a web browser, instead bundle system data files in
// the WASM binary using include_dir. For now, no support for saving files.

pub use crate::io::*;
use crate::Timer;
use serde::de::DeserializeOwned;
Expand All @@ -6,8 +9,22 @@ use std::io::{Error, ErrorKind};

static SYSTEM_DATA: include_dir::Dir = include_dir::include_dir!("../data/system");

pub fn write_json<T: Serialize>(_path: String, _obj: &T) {
// TODO not yet
pub fn file_exists<I: Into<String>>(path: I) -> bool {
SYSTEM_DATA
.get_file(path.into().trim_start_matches("../data/system/"))
.is_some()
}

pub fn list_dir(dir: String) -> Vec<String> {
let mut results = Vec::new();
if let Some(dir) = SYSTEM_DATA.get_dir(dir.trim_start_matches("../data/system/")) {
for f in dir.files() {
results.push(format!("../data/system/{}", f.path().display()));
}
} else {
error!("Can't list_dir({})", dir);
}
results
}

pub fn slurp_file(path: &str) -> Result<Vec<u8>, Error> {
Expand All @@ -21,10 +38,6 @@ pub fn slurp_file(path: &str) -> Result<Vec<u8>, Error> {
}
}

pub fn write_binary<T: Serialize>(_path: String, _obj: &T) {
// TODO
}

pub fn maybe_read_binary<T: DeserializeOwned>(
path: String,
_timer: &mut Timer,
Expand All @@ -41,34 +54,12 @@ pub fn maybe_read_binary<T: DeserializeOwned>(
}
}

pub fn list_all_objects(dir: String) -> Vec<String> {
let mut results = Vec::new();
if let Some(dir) = SYSTEM_DATA.get_dir(dir.trim_start_matches("../data/system/")) {
for f in dir.files() {
results.push(format!("../data/system/{}", f.path().display()));
}
} else {
panic!("Can't list_all_objects in {}", dir);
}
results
pub fn write_json<T: Serialize>(_path: String, _obj: &T) {
// TODO not yet
}

pub fn file_exists<I: Into<String>>(path: I) -> bool {
SYSTEM_DATA
.get_file(path.into().trim_start_matches("../data/system/"))
.is_some()
pub fn write_binary<T: Serialize>(_path: String, _obj: &T) {
// TODO
}

pub fn delete_file<I: Into<String>>(_path: I) {}

pub fn list_dir(dir: String) -> Vec<String> {
let mut results = Vec::new();
if let Some(dir) = SYSTEM_DATA.get_dir(dir.trim_start_matches("../data/system/")) {
for f in dir.files() {
results.push(format!("../data/system/{}", f.path().display()));
}
} else {
error!("Can't list_dir({})", dir);
}
results
}

0 comments on commit 5706226

Please sign in to comment.