Repository: vitiral/path_abs (language: rust)

Issue:
add wasm32-wasi target
It would be great if we could target WASI. Currently:

```
Camerons-MacBook-Pro:path_abs cameron$ cargo build --target wasm32-wasi
    Updating crates.io index
   Compiling proc-macro2 v1.0.21
   Compiling memchr v2.3.3
   Compiling unicode-xid v0.2.1
   Compiling lazy_static v1.4.0
   Compiling syn v1.0.41
   Compiling serde_derive v1.0.116
   Compiling regex-syntax v0.6.18
   Compiling serde v1.0.116
   Compiling std_prelude v0.2.12
   Compiling thread_local v1.0.1
   Compiling aho-corasick v0.7.13
   Compiling quote v1.0.7
   Compiling regex v1.3.9
   Compiling stfu8 v0.2.4
   Compiling path_abs v0.5.0 (/Users/cameron/rs/path_abs)
error[E0425]: cannot find function `symlink_dir` in this scope
   --> src/dir.rs:308:9
    |
308 |         symlink_dir(&self, &dst).map_err(|err| {
    |         ^^^^^^^^^^^-------------
    |         |
    |         help: try calling `symlink_dir` as a method: `self.symlink_dir(&dst)`

error[E0425]: cannot find function `symlink_file` in this scope
   --> src/file.rs:413:9
    |
413 |         symlink_file(&self, &dst).map_err(|err| {
    |         ^^^^^^^^^^^^-------------
    |         |
    |         help: try calling `symlink_file` as a method: `self.symlink_file(&dst)`

warning: unused import: `OsString`
  --> src/ser.rs:16:23
   |
16 | use std::ffi::{OsStr, OsString};
   |                       ^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

error[E0046]: not all trait items implemented, missing: `to_stfu8`
   --> src/ser.rs:150:1
    |
28  |       fn to_stfu8(&self) -> String;
    |       ----------------------------- `to_stfu8` from trait
...
150 | / impl<T> ToStfu8 for T
151 | | where
152 | |     T: Borrow<PathBuf>,
153 | | {
...   |
164 | |     }
165 | | }
    | |_^ missing `to_stfu8` in implementation

error[E0046]: not all trait items implemented, missing: `from_stfu8`
   --> src/ser.rs:167:1
    |
32  |       fn from_stfu8(s: &str) -> Result<Self, stfu8::DecodeError>;
    |       ----------------------------------------------------------- `from_stfu8` from trait
...
167 | / impl<T> FromStfu8 for T
168 | | where
169 | |     T: From<PathBuf>,
170 | | {
...   |
185 | |     }
186 | | }
    | |_^ missing `from_stfu8` in implementation

warning: use of deprecated associated function `std::error::Error::description`: use the Display impl or to_string()
   --> src/lib.rs:338:21
    |
338 |         self.io_err.description()
    |                     ^^^^^^^^^^^
    |
    = note: `#[warn(deprecated)]` on by default

error: aborting due to 4 previous errors; 2 warnings emitted

Some errors have detailed explanations: E0046, E0425.
For more information about an error, try `rustc --explain E0046`.
error: could not compile `path_abs`

To learn more, run the command again with --verbose.
```


Discussion / hints:
For my use case, I'm just [using](https://github.com/ctaggart/autorust/pull/6/commits/d71551f7cd6e43fce56b9e8bb7f82699cdc16397#diff-05ae2860d8363fe09edd7dbc4a2f7e41R7-R10) `pop_up` and `append` that come from `PathMut`:

``` rust
use path_abs::PathMut;
use std::path::PathBuf;

use super::Result;

pub fn path_join(a: &str, b: &str) -> Result<String> {
    let mut c = PathBuf::from(a);
    c.pop_up()?; // to directory
    c.append(b)?;
    Ok(c.as_path().to_str().unwrap().to_owned())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_path_join() -> Result<()> {
        let a = "../azure-rest-api-specs/specification/vmware/resource-manager/Microsoft.AVS/stable/2020-03-20/vmware.json";
        let b = "../../../../../common-types/resource-management/v1/types.json";
        let c = path_join(a, b)?;
        assert_eq!(
            c,
            "../azure-rest-api-specs/specification/common-types/resource-management/v1/types.json"
        );
        Ok(())
    }
}
```
Agreed! I'm not actively using this library but will review and merge a PR.

Fix patch:
diff --git a/src/dir.rs b/src/dir.rs
index 34182d8..2490e62 100644
--- a/src/dir.rs
+++ b/src/dir.rs
@@ -523,6 +523,12 @@ impl PathOps for PathDir {
     }
 }
 
+#[cfg(target_os = "wasi")]
+fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+    let file = std::fs::File::open(&src)?;
+    std::os::wasi::fs::symlink(src, &file, dst)
+}
+
 #[cfg(unix)]
 fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
     ::std::os::unix::fs::symlink(src, dst)
diff --git a/src/file.rs b/src/file.rs
index b712350..335d11a 100644
--- a/src/file.rs
+++ b/src/file.rs
@@ -570,6 +570,12 @@ impl PathOps for PathFile {
     }
 }
 
+#[cfg(target_os = "wasi")]
+fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+    let file = std::fs::File::open(&src)?;
+    std::os::wasi::fs::symlink(src, &file, dst)
+}
+
 #[cfg(unix)]
 fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
     ::std::os::unix::fs::symlink(src, dst)
diff --git a/src/lib.rs b/src/lib.rs
index b9f7310..032ec38 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -203,6 +203,9 @@
 //! [`PathOps`]: trait.PathOps.html
 //! [`PathMut`]: trait.PathMut.html
 
+#![cfg_attr(target_os = "wasi",
+            feature(wasi_ext))]
+
 #[cfg(feature = "serialize")]
 extern crate serde;
 #[macro_use]
diff --git a/src/ser.rs b/src/ser.rs
index 9e2e407..d5694f5 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -14,6 +14,8 @@ use stfu8;
 use super::{PathMut, PathOps};
 
 use std::ffi::{OsStr, OsString};
+#[cfg(target_os = "wasi")]
+use std::os::wasi::ffi::{OsStrExt, OsStringExt};
 #[cfg(unix)]
 use std::os::unix::ffi::{OsStrExt, OsStringExt};
 #[cfg(windows)]
@@ -151,7 +153,7 @@ impl<T> ToStfu8 for T
 where
     T: Borrow<PathBuf>,
 {
-    #[cfg(unix)]
+    #[cfg(any(target_os = "wasi", unix))]
     fn to_stfu8(&self) -> String {
         let bytes = self.borrow().as_os_str().as_bytes();
         stfu8::encode_u8(bytes)
@@ -168,7 +170,7 @@ impl<T> FromStfu8 for T
 where
     T: From<PathBuf>,
 {
-    #[cfg(unix)]
+    #[cfg(any(target_os = "wasi", unix))]
     fn from_stfu8(s: &str) -> Result<T, stfu8::DecodeError> {
         let raw_path = stfu8::decode_u8(s)?;
         let os_str = OsString::from_vec(raw_path);
@@ -252,7 +254,7 @@ mod tests {
     use super::super::{PathDir, PathFile, PathInfo, PathMut, PathOps, PathType};
     use super::*;
 
-    #[cfg(unix)]
+    #[cfg(any(target_os = "wasi", unix))]
     static SERIALIZED: &str = "[\
                                {\"type\":\"file\",\"path\":\"{0}/foo.txt\"},\
                                {\"type\":\"dir\",\"path\":\"{0}/bar\"},\


Test patch: