From 70f4b2036445a6b8c92da5aef06d22e9548587c5 Mon Sep 17 00:00:00 2001
From: Luca Barbato <lu_zero@gentoo.org>
Date: Mon, 13 Aug 2018 09:43:39 +0200
Subject: [PATCH] Move the clap dependency outside the library

---
 Cargo.toml          |   4 +-
 src/bin/common.rs   |  89 ++++++++++++++++++++++++++++++++++++
 src/bin/rav1e.rs    |   1 +
 src/bin/rav1repl.rs |   1 +
 src/lib.rs          |  95 ++------------------------------------
 src/util.rs         | 109 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 207 insertions(+), 92 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 93200843..be0fd541 100755
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,12 +11,12 @@ autobins = false
 repl = ["rustyline", "binaries"]
 comparative_bench = []
 decode_test = ["bindgen"]
-binaries = ["y4m"]
+binaries = ["y4m", "clap"]
 default = ["binaries"]
 
 [dependencies]
 bitstream-io = "0.6"
-clap = "2"
+clap = { version = "2", optional = true }
 libc = "0.2"
 rand = "0.5"
 rustyline = { version = "1", optional = true }
diff --git a/src/bin/common.rs b/src/bin/common.rs
index b1f107b0..41b20941 100644
--- a/src/bin/common.rs
+++ b/src/bin/common.rs
@@ -1,7 +1,96 @@
 use y4m;
 use rav1e::*;
+use std::fs::File;
+use std::io;
 use std::io::prelude::*;
 use std::slice;
+use clap::{App, Arg};
+
+pub struct EncoderIO {
+    pub input: Box<Read>,
+    pub output: Box<Write>,
+    pub rec: Option<Box<Write>>,
+}
+
+pub trait FromCli {
+    fn from_cli() -> (EncoderIO, EncoderConfig);
+}
+
+impl FromCli for EncoderConfig {
+    fn from_cli() -> (EncoderIO, EncoderConfig) {
+        let matches = App::new("rav1e")
+            .version("0.1.0")
+            .about("AV1 video encoder")
+           .arg(Arg::with_name("INPUT")
+                .help("Uncompressed YUV4MPEG2 video input")
+                .required(true)
+                .index(1))
+            .arg(Arg::with_name("OUTPUT")
+                .help("Compressed AV1 in IVF video output")
+                .short("o")
+                .long("output")
+                .required(true)
+                .takes_value(true))
+            .arg(Arg::with_name("RECONSTRUCTION")
+                .short("r")
+                .takes_value(true))
+            .arg(Arg::with_name("LIMIT")
+                .help("Maximum number of frames to encode")
+                .short("l")
+                .long("limit")
+                .takes_value(true)
+                .default_value("0"))
+            .arg(Arg::with_name("QP")
+                .help("Quantizer (0-255)")
+                .long("quantizer")
+                .takes_value(true)
+                .default_value("100"))
+            .arg(Arg::with_name("SPEED")
+                .help("Speed level (0(slow)-10(fast))")
+                .short("s")
+                .long("speed")
+                .takes_value(true)
+                .default_value("3"))
+            .arg(Arg::with_name("TUNE")
+                .help("Quality tuning (Will enforce partition sizes >= 8x8)")
+                .long("tune")
+                .possible_values(&Tune::variants())
+                .default_value("psnr")
+                .case_insensitive(true))
+            .get_matches();
+
+
+        let io = EncoderIO {
+            input: match matches.value_of("INPUT").unwrap() {
+                "-" => Box::new(io::stdin()) as Box<Read>,
+                f => Box::new(File::open(&f).unwrap()) as Box<Read>
+            },
+            output: match matches.value_of("OUTPUT").unwrap() {
+                "-" => Box::new(io::stdout()) as Box<Write>,
+                f => Box::new(File::create(&f).unwrap()) as Box<Write>
+            },
+            rec: matches.value_of("RECONSTRUCTION").map(|f| {
+                Box::new(File::create(&f).unwrap()) as Box<Write>
+            })
+        };
+
+        let config = EncoderConfig {
+            limit: matches.value_of("LIMIT").unwrap().parse().unwrap(),
+            quantizer: matches.value_of("QP").unwrap().parse().unwrap(),
+            speed: matches.value_of("SPEED").unwrap().parse().unwrap(),
+            tune: matches.value_of("TUNE").unwrap().parse().unwrap()
+        };
+
+        // Validate arguments
+        if config.quantizer == 0 {
+            unimplemented!();
+        } else if config.quantizer > 255 || config.speed > 10 {
+            panic!("argument out of range");
+        }
+
+        (io, config)
+    }
+}
 
 /// Encode and write a frame.
 pub fn process_frame(sequence: &mut Sequence, fi: &mut FrameInvariants,
diff --git a/src/bin/rav1e.rs b/src/bin/rav1e.rs
index af2e34cb..240db3b6 100755
--- a/src/bin/rav1e.rs
+++ b/src/bin/rav1e.rs
@@ -9,6 +9,7 @@
 
 extern crate rav1e;
 extern crate y4m;
+extern crate clap;
 
 mod common;
 use common::*;
diff --git a/src/bin/rav1repl.rs b/src/bin/rav1repl.rs
index f9a10049..cae2c40b 100644
--- a/src/bin/rav1repl.rs
+++ b/src/bin/rav1repl.rs
@@ -9,6 +9,7 @@
 
 extern crate rustyline;
 extern crate y4m;
+extern crate clap;
 
 extern crate rav1e;
 
diff --git a/src/lib.rs b/src/lib.rs
index 289e1e42..b03cb50b 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,8 +12,6 @@
 
 extern crate bitstream_io;
 extern crate backtrace;
-#[macro_use]
-extern crate clap;
 extern crate libc;
 extern crate rand;
 
@@ -22,10 +20,8 @@ extern crate enum_iterator_derive;
 
 extern crate num_traits;
 
-use std::fs::File;
 use std::io::prelude::*;
 use bitstream_io::{BE, LE, BitWriter};
-use clap::{App, Arg};
 use std::rc::Rc;
 use std::*;
 
@@ -37,6 +33,7 @@ pub mod transform;
 pub mod quantize;
 pub mod predict;
 pub mod rdo;
+#[macro_use]
 pub mod util;
 pub mod cdef;
 
@@ -185,12 +182,12 @@ impl Sequence {
         assert!(width_bits <= 16);
         assert!(height_bits <= 16);
 
-        let profile = if bit_depth == 12 { 
+        let profile = if bit_depth == 12 {
             2
         } else if chroma_sampling == ChromaSampling::Cs444 {
             1
         } else {
-            0 
+            0
         };
 
         let mut operating_point_idc = [0 as u16; MAX_NUM_OPERATING_POINTS];
@@ -447,12 +444,6 @@ impl fmt::Display for FrameType{
     }
 }
 
-pub struct EncoderIO {
-    pub input: Box<Read>,
-    pub output: Box<Write>,
-    pub rec: Option<Box<Write>>,
-}
-
 #[derive(Copy, Clone, Debug)]
 pub struct EncoderConfig {
     pub limit: u64,
@@ -472,82 +463,6 @@ impl Default for EncoderConfig {
     }
 }
 
-impl EncoderConfig {
-    pub fn from_cli() -> (EncoderIO, EncoderConfig) {
-        let matches = App::new("rav1e")
-            .version("0.1.0")
-            .about("AV1 video encoder")
-           .arg(Arg::with_name("INPUT")
-                .help("Uncompressed YUV4MPEG2 video input")
-                .required(true)
-                .index(1))
-            .arg(Arg::with_name("OUTPUT")
-                .help("Compressed AV1 in IVF video output")
-                .short("o")
-                .long("output")
-                .required(true)
-                .takes_value(true))
-            .arg(Arg::with_name("RECONSTRUCTION")
-                .short("r")
-                .takes_value(true))
-            .arg(Arg::with_name("LIMIT")
-                .help("Maximum number of frames to encode")
-                .short("l")
-                .long("limit")
-                .takes_value(true)
-                .default_value("0"))
-            .arg(Arg::with_name("QP")
-                .help("Quantizer (0-255)")
-                .long("quantizer")
-                .takes_value(true)
-                .default_value("100"))
-            .arg(Arg::with_name("SPEED")
-                .help("Speed level (0(slow)-10(fast))")
-                .short("s")
-                .long("speed")
-                .takes_value(true)
-                .default_value("3"))
-            .arg(Arg::with_name("TUNE")
-                .help("Quality tuning (Will enforce partition sizes >= 8x8)")
-                .long("tune")
-                .possible_values(&Tune::variants())
-                .default_value("psnr")
-                .case_insensitive(true))
-            .get_matches();
-
-
-        let io = EncoderIO {
-            input: match matches.value_of("INPUT").unwrap() {
-                "-" => Box::new(std::io::stdin()) as Box<Read>,
-                f => Box::new(File::open(&f).unwrap()) as Box<Read>
-            },
-            output: match matches.value_of("OUTPUT").unwrap() {
-                "-" => Box::new(std::io::stdout()) as Box<Write>,
-                f => Box::new(File::create(&f).unwrap()) as Box<Write>
-            },
-            rec: matches.value_of("RECONSTRUCTION").map(|f| {
-                Box::new(File::create(&f).unwrap()) as Box<Write>
-            })
-        };
-
-        let config = EncoderConfig {
-            limit: matches.value_of("LIMIT").unwrap().parse().unwrap(),
-            quantizer: matches.value_of("QP").unwrap().parse().unwrap(),
-            speed: matches.value_of("SPEED").unwrap().parse().unwrap(),
-            tune: matches.value_of("TUNE").unwrap().parse().unwrap()
-        };
-
-        // Validate arguments
-        if config.quantizer == 0 {
-            unimplemented!();
-        } else if config.quantizer > 255 || config.speed > 10 {
-            panic!("argument out of range");
-        }
-
-        (io, config)
-    }
-}
-
 pub fn write_ivf_header(output_file: &mut Write, width: usize, height: usize, num: usize, den: usize) {
     let mut bw = BitWriter::<LE>::new(output_file);
     bw.write_bytes(b"DKIF").unwrap();
@@ -721,7 +636,7 @@ impl<'a> UncompressedHeader for BitWriter<'a, BE> {
         } else {
             unimplemented!(); // 4:4:4 sampling at 8 or 10 bits
         }
-        
+
         self.write_bit(false)?; // No color description present
 
         if seq.monochrome {
@@ -1860,7 +1775,7 @@ mod test_encode_decode {
 
     }
 
-    fn setup_encoder(w: usize, h: usize, speed: usize, quantizer: usize, 
+    fn setup_encoder(w: usize, h: usize, speed: usize, quantizer: usize,
         bit_depth: usize, chroma_sampling: ChromaSampling) -> (FrameInvariants, Sequence) {
         unsafe {
             av1_rtcd();
diff --git a/src/util.rs b/src/util.rs
index c9770fc5..ccc4b691 100755
--- a/src/util.rs
+++ b/src/util.rs
@@ -7,6 +7,115 @@
 // Media Patent License 1.0 was not distributed with this source code in the
 // PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 
+// Imported from clap, to avoid to depend directly to the crate
+macro_rules! _clap_count_exprs {
+    () => { 0 };
+    ($e:expr) => { 1 };
+    ($e:expr, $($es:expr),+) => { 1 + _clap_count_exprs!($($es),*) };
+}
+macro_rules! arg_enum {
+    (@as_item $($i:item)*) => ($($i)*);
+    (@impls ( $($tts:tt)* ) -> ($e:ident, $($v:ident),+)) => {
+        arg_enum!(@as_item
+        $($tts)*
+
+        impl ::std::str::FromStr for $e {
+            type Err = String;
+
+            fn from_str(s: &str) -> ::std::result::Result<Self,Self::Err> {
+                #[allow(deprecated, unused_imports)]
+                use ::std::ascii::AsciiExt;
+                match s {
+                    $(stringify!($v) |
+                    _ if s.eq_ignore_ascii_case(stringify!($v)) => Ok($e::$v)),+,
+                    _ => Err({
+                        let v = vec![
+                            $(stringify!($v),)+
+                        ];
+                        format!("valid values: {}",
+                            v.join(" ,"))
+                    }),
+                }
+            }
+        }
+        impl ::std::fmt::Display for $e {
+            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+                match *self {
+                    $($e::$v => write!(f, stringify!($v)),)+
+                }
+            }
+        }
+        impl $e {
+            #[allow(dead_code)]
+            pub fn variants() -> [&'static str; _clap_count_exprs!($(stringify!($v)),+)] {
+                [
+                    $(stringify!($v),)+
+                ]
+            }
+        });
+    };
+    ($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
+        arg_enum!(@impls
+            ($(#[$($m),+])+
+            pub enum $e {
+                $($v$(=$val)*),+
+            }) -> ($e, $($v),+)
+        );
+    };
+    ($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
+        arg_enum!(@impls
+            ($(#[$($m),+])+
+            pub enum $e {
+                $($v$(=$val)*),+
+            }) -> ($e, $($v),+)
+        );
+    };
+    ($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
+        arg_enum!(@impls
+            ($(#[$($m),+])+
+             enum $e {
+                 $($v$(=$val)*),+
+             }) -> ($e, $($v),+)
+        );
+    };
+    ($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
+        arg_enum!(@impls
+            ($(#[$($m),+])+
+            enum $e {
+                $($v$(=$val)*),+
+            }) -> ($e, $($v),+)
+        );
+    };
+    (pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
+        arg_enum!(@impls
+            (pub enum $e {
+                $($v$(=$val)*),+
+            }) -> ($e, $($v),+)
+        );
+    };
+    (pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
+        arg_enum!(@impls
+            (pub enum $e {
+                $($v$(=$val)*),+
+            }) -> ($e, $($v),+)
+        );
+    };
+    (enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
+        arg_enum!(@impls
+            (enum $e {
+                $($v$(=$val)*),+
+            }) -> ($e, $($v),+)
+        );
+    };
+    (enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
+        arg_enum!(@impls
+            (enum $e {
+                $($v$(=$val)*),+
+            }) -> ($e, $($v),+)
+        );
+    };
+}
+
 #[repr(align(16))]
 struct Align16;
 
-- 
GitLab