Skip to content

Commit

Permalink
Merge pull request #20 from paolobarbolini/docs-1
Browse files Browse the repository at this point in the history
Improve documentation and examples
  • Loading branch information
paolobarbolini committed Jul 20, 2020
2 parents ee7ae69 + dd17f00 commit f4635f8
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 103 deletions.
76 changes: 41 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,66 +19,72 @@ Does not require magic file database (i.e. `/etc/magic`).
- File discovery by class (image, video, audio...)
- Supports custom new types and matchers

## Documentation

https://docs.rs/infer

## Installation

This crate works with Cargo and is on
[crates.io](https://crates.io/crates/infer). Add it to your `Cargo.toml`
like so:
This crate works with Cargo and is on [crates.io](https://crates.io/crates/infer).
Add it to your `Cargo.toml` like so:

```toml
[dependencies]
infer = "0.2"
```

If you are not using the custom matcher or the file type from file path functionality you
can make this crate even lighter by importing it with no default features, like so:

```toml
[dependencies]
infer = { version = "0.2", default-features = false }
```

## no_std and no_alloc support

This crate supports `no_std` and `no_alloc` environments. `std` support is enabled by default,
but you can disable it by importing the crate with no default features, making it depend
only on the Rust `core` Library.

`alloc` has to be enabled to be able to use custom file matchers.

`std` has to be enabled to be able to get the file type from a file given the file path.

## Examples

Most operations can be done via _top level functions_, but they are also available through the `Infer`
struct, which must be used when dealing custom matchers.

### Get the type of a buffer

```rust
use infer::Infer;
let buf = [0xFF, 0xD8, 0xFF, 0xAA];
let kind = infer::get(&buf).expect("file type is known");

let v = vec![0xFF, 0xD8, 0xFF, 0xAA];
let info = Infer::new();

assert_eq!("image/jpeg", info.get(&v).unwrap().mime);
assert_eq!("jpg", info.get(&v).unwrap().ext);
assert_eq!(kind.mime_type(), "image/jpeg");
assert_eq!(kind.extension(), "jpg");
```

### Check path
### Check file type by path

```rust
use infer::Infer;

let info = Infer::new();
let res = info.get_from_path("testdata/sample.jpg");

assert!(res.is_ok());
let o = res.unwrap();
assert!(o.is_some());
let typ = o.unwrap();
let kind = infer::get_from_path("testdata/sample.jpg")
.expect("file read successfully")
.expect("file type is known");

assert_eq!("image/jpeg", typ.mime);
assert_eq!("jpg", typ.ext);
assert_eq!(kind.mime_type(), "image/jpeg");
assert_eq!(kind.extension(), "jpg");
```

### Check for specific type

```rust
let v = vec![0xFF, 0xD8, 0xFF, 0xAA];
assert!(infer::image::is_jpeg(&v));
let buf = [0xFF, 0xD8, 0xFF, 0xAA];
assert!(infer::image::is_jpeg(&buf));
```

### Check for specific type class
Note individual matcher functions do not require init

```rust
let v = vec![0xFF, 0xD8, 0xFF, 0xAA];
let info = infer::Infer::new();
assert!(info.is_image(&v));
let buf = [0xFF, 0xD8, 0xFF, 0xAA];
assert!(infer::is_image(&buf));
```

### Adds a custom file type matcher
Expand All @@ -91,11 +97,11 @@ fn custom_matcher(buf: &[u8]) -> bool {
let mut info = infer::Infer::new();
info.add("custom/foo", "foo", custom_matcher);

let v = vec![0x10, 0x11, 0x12, 0x13];
let res = info.get(&v).unwrap();
let buf = [0x10, 0x11, 0x12, 0x13];
let kind = info.get(&buf).expect("file type is known");

assert_eq!("custom/foo", res.mime);
assert_eq!("foo", res.ext);
assert_eq!(kind.mime_type(), "custom/foo");
assert_eq!(kind.extension(), "foo");
```

## Supported types
Expand Down
136 changes: 68 additions & 68 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,47 @@ Small crate to infer file and MIME type by checking the
### Get the type of a buffer
```rust
let v = [0xFF, 0xD8, 0xFF, 0xAA];
let info = infer::Infer::new();
assert_eq!("image/jpeg", info.get(&v).unwrap().mime_type());
assert_eq!("jpg", info.get(&v).unwrap().extension());
let buf = [0xFF, 0xD8, 0xFF, 0xAA];
let kind = infer::get(&buf).expect("file type is known");
assert_eq!(kind.mime_type(), "image/jpeg");
assert_eq!(kind.extension(), "jpg");
```
### Check path
### Check file type by path
```rust
# #[cfg(feature = "std")]
# fn run() {
let res = infer::get_from_path("testdata/sample.jpg");
assert!(res.is_ok());
let o = res.unwrap();
assert!(o.is_some());
let typ = o.unwrap();
assert_eq!("image/jpeg", typ.mime_type());
assert_eq!("jpg", typ.extension());
let kind = infer::get_from_path("testdata/sample.jpg")
.expect("file read successfully")
.expect("file type is known");
assert_eq!(kind.mime_type(), "image/jpeg");
assert_eq!(kind.extension(), "jpg");
# }
```
### Check for specific type
Note individual matcher functions do not require an Infer struct instance.
```rust
let v = [0xFF, 0xD8, 0xFF, 0xAA];
assert!(infer::image::is_jpeg(&v));
let buf = [0xFF, 0xD8, 0xFF, 0xAA];
assert!(infer::image::is_jpeg(&buf));
```
### Check for specific type class
```rust
let v = [0xFF, 0xD8, 0xFF, 0xAA];
assert!(infer::is_image(&v));
let buf = [0xFF, 0xD8, 0xFF, 0xAA];
assert!(infer::is_image(&buf));
```
### Adds a custom file type matcher
Here we actually need to use the `Infer` struct to be able to declare custom matchers.
```rust
# #[cfg(feature = "std")]
# #[cfg(feature = "alloc")]
# fn run() {
fn custom_matcher(buf: &[u8]) -> bool {
return buf.len() >= 3 && buf[0] == 0x10 && buf[1] == 0x11 && buf[2] == 0x12;
Expand All @@ -56,11 +56,11 @@ fn custom_matcher(buf: &[u8]) -> bool {
let mut info = infer::Infer::new();
info.add("custom/foo", "foo", custom_matcher);
let v = [0x10, 0x11, 0x12, 0x13];
let res = info.get(&v).unwrap();
let buf = [0x10, 0x11, 0x12, 0x13];
let kind = info.get(&buf).unwrap();
assert_eq!("custom/foo", res.mime_type());
assert_eq!("foo", res.extension());
assert_eq!(kind.mime_type(), "custom/foo");
assert_eq!(kind.extension(), "foo");
# }
```
*/
Expand Down Expand Up @@ -172,6 +172,10 @@ impl PartialEq for Type {
}

/// Infer allows to use a custom set of `Matcher`s for infering a MIME type.
///
/// Most operations can be done by using the _top level functions_, but when custom matchers
/// are needed every call has to go through the `Infer` struct to be able
/// to see the custom matchers.
pub struct Infer {
#[cfg(feature = "alloc")]
mmap: Vec<Type>,
Expand Down Expand Up @@ -203,9 +207,11 @@ impl Infer {
///
/// ```rust
/// let info = infer::Infer::new();
/// let v = [0xFF, 0xD8, 0xFF, 0xAA];
/// assert_eq!("image/jpeg", info.get(&v).unwrap().mime_type());
/// assert_eq!("jpg", info.get(&v).unwrap().extension());
/// let buf = [0xFF, 0xD8, 0xFF, 0xAA];
/// let kind = info.get(&buf).expect("file type is known");
///
/// assert_eq!(kind.mime_type(), "image/jpeg");
/// assert_eq!(kind.extension(), "jpg");
/// ```
pub fn get(&self, buf: &[u8]) -> Option<Type> {
self.iter_matchers().find(|kind| kind.matches(buf)).copied()
Expand Down Expand Up @@ -243,7 +249,6 @@ impl Infer {
/// Returns the `Type` from a file extension.
///
/// See [`get_from_ext`](./fn.get_from_ext.html).
/// ```
pub fn get_from_ext<S: AsRef<str>>(&self, val: S) -> Option<Type> {
let val = val.as_ref();
self.iter_matchers()
Expand Down Expand Up @@ -367,8 +372,8 @@ impl Infer {
///
/// let mut info = infer::Infer::new();
/// info.add("custom/foo", "foo", custom_matcher);
/// let v = [0x10, 0x11, 0x12, 0x13];
/// assert!(info.is_custom(&v));
/// let buf = [0x10, 0x11, 0x12, 0x13];
/// assert!(info.is_custom(&buf));
/// # }
/// ```
pub fn is_custom(&self, buf: &[u8]) -> bool {
Expand All @@ -389,10 +394,11 @@ impl Infer {
///
/// let mut info = infer::Infer::new();
/// info.add("custom/foo", "foo", custom_matcher);
/// let v = [0x10, 0x11, 0x12, 0x13];
/// let res = info.get(&v).unwrap();
/// assert_eq!("custom/foo", res.mime_type());
/// assert_eq!("foo", res.extension());
/// let buf = [0x10, 0x11, 0x12, 0x13];
/// let kind = info.get(&buf).expect("file type is known");
///
/// assert_eq!(kind.mime_type(), "custom/foo");
/// assert_eq!(kind.extension(), "foo");
/// ```
#[cfg(feature = "alloc")]
pub fn add(&mut self, mime_type: &'static str, extension: &'static str, m: Matcher) {
Expand Down Expand Up @@ -423,9 +429,12 @@ static INFER: Infer = Infer::new();
/// # Examples
///
/// ```rust
/// let v = [0xFF, 0xD8, 0xFF, 0xAA];
/// assert_eq!("image/jpeg", infer::get(&v).unwrap().mime_type());
/// assert_eq!("jpg", infer::get(&v).unwrap().extension());
/// let info = infer::Infer::new();
/// let buf = [0xFF, 0xD8, 0xFF, 0xAA];
/// let kind = info.get(&buf).expect("file type is known");
///
/// assert_eq!(kind.mime_type(), "image/jpeg");
/// assert_eq!(kind.extension(), "jpg");
/// ```
pub fn get(buf: &[u8]) -> Option<Type> {
INFER.get(buf)
Expand All @@ -440,13 +449,12 @@ pub fn get(buf: &[u8]) -> Option<Type> {
/// # Examples
///
/// ```rust
/// let res = infer::get_from_path("testdata/sample.jpg");
/// assert!(res.is_ok());
/// let o = res.unwrap();
/// assert!(o.is_some());
/// let typ = o.unwrap();
/// assert_eq!("image/jpeg", typ.mime_type());
/// assert_eq!("jpg", typ.extension());
/// let kind = infer::get_from_path("testdata/sample.jpg")
/// .expect("file read successfully")
/// .expect("file type is known");
///
/// assert_eq!(kind.mime_type(), "image/jpeg");
/// assert_eq!(kind.extension(), "jpg");
/// ```
#[cfg(feature = "std")]
pub fn get_from_path<P: AsRef<Path>>(path: P) -> io::Result<Option<Type>> {
Expand All @@ -458,11 +466,9 @@ pub fn get_from_path<P: AsRef<Path>>(path: P) -> io::Result<Option<Type>> {
/// # Examples
///
/// ```rust
/// let res = infer::get_from_str("video/mp4");
/// assert!(res.is_some());
/// let typ = res.unwrap();
/// assert_eq!(typ.mime_type(), "video/mp4");
/// assert_eq!(typ.extension(), "mp4");
/// let kind = infer::get_from_str("video/mp4").expect("mime type is known");
/// assert_eq!(kind.mime_type(), "video/mp4");
/// assert_eq!(kind.extension(), "mp4");
/// ```
pub fn get_from_str<S: AsRef<str>>(val: S) -> Option<Type> {
INFER.get_from_str(val)
Expand All @@ -473,11 +479,9 @@ pub fn get_from_str<S: AsRef<str>>(val: S) -> Option<Type> {
/// # Examples
///
/// ```rust
/// let res = infer::get_from_ext("jpg");
/// assert!(res.is_some());
/// let typ = res.unwrap();
/// assert_eq!(typ.mime_type(), "image/jpeg");
/// assert_eq!(typ.extension(), "jpg");
/// let kind = infer::get_from_ext("jpg").expect("extension is known");
/// assert_eq!(kind.mime_type(), "image/jpeg");
/// assert_eq!(kind.extension(), "jpg");
/// ```
pub fn get_from_ext<S: AsRef<str>>(val: S) -> Option<Type> {
INFER.get_from_ext(val)
Expand All @@ -488,8 +492,8 @@ pub fn get_from_ext<S: AsRef<str>>(val: S) -> Option<Type> {
/// # Examples
///
/// ```rust
/// let v = [0xFF, 0xD8, 0xFF, 0xAA];
/// assert!(infer::is(&v, "jpg"));
/// let buf = [0xFF, 0xD8, 0xFF, 0xAA];
/// assert!(infer::is(&buf, "jpg"));
/// ```
pub fn is(buf: &[u8], extension: &str) -> bool {
INFER.is(buf, extension)
Expand All @@ -500,8 +504,8 @@ pub fn is(buf: &[u8], extension: &str) -> bool {
/// # Examples
///
/// ```rust
/// let v = [0xFF, 0xD8, 0xFF, 0xAA];
/// assert!(infer::is_mime(&v, "image/jpeg"));
/// let buf = [0xFF, 0xD8, 0xFF, 0xAA];
/// assert!(infer::is_mime(&buf, "image/jpeg"));
/// ```
pub fn is_mime(buf: &[u8], mime_type: &str) -> bool {
INFER.is_mime(buf, mime_type)
Expand Down Expand Up @@ -615,25 +619,21 @@ pub fn is_video(buf: &[u8]) -> bool {

#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
use super::Infer;

#[test]
fn test_get_unknown() {
let v = [];
let info = Infer::new();
assert!(info.get(&v).is_none());
let buf = [];
assert!(crate::get(&buf).is_none());
}

#[test]
fn test_get_jpeg() {
let v = [0xFF, 0xD8, 0xFF, 0xAA];
match crate::get(&v) {
Some(info) => {
assert_eq!(info.extension(), "jpg");
assert_eq!(info.mime_type(), "image/jpeg");
}
None => panic!("type info expected"),
}
let buf = [0xFF, 0xD8, 0xFF, 0xAA];
let kind = crate::get(&buf).expect("file type is known");
assert_eq!(kind.extension(), "jpg");
assert_eq!(kind.mime_type(), "image/jpeg");
}

#[cfg(feature = "alloc")]
Expand Down

0 comments on commit f4635f8

Please sign in to comment.