<commit_before>extern crate leaf;
extern crate collenchyma as co;

#[cfg(test)]
mod layer_spec {
    use std::rc::Rc;
    use co::prelude::*;
    use leaf::layer::*;

    fn new_layer_config() -> LayerConfig {
        LayerConfig::new("foo", LayerType::Sigmoid)
    }

    fn native_backend() -> Rc<Backend<Native>> {
        Rc::new(Backend::<Native>::default().unwrap())
    }

    #[cfg(feature="cuda")]
    fn cuda_backend() -> Rc<Backend<Cuda>> {
        Rc::new(Backend::<Cuda>::default().unwrap())
    }

    #[cfg(all(feature="native", feature="cuda"))]
    mod native_cuda {
        use leaf::layer::*;
        use leaf::layers::*;
        use super::{native_backend, cuda_backend};

        #[test]
        fn create_layer_with_either() {
            let cfg = super::new_layer_config();
            Layer::from_config(native_backend(), &cfg);

            let cfg = super::new_layer_config();
            Layer::from_config(cuda_backend(), &cfg);
        }
    }

    #[cfg(feature="native")]
    mod native {
        use co::prelude::*;
        use leaf::layer::*;
        use leaf::layers::*;
        use super::native_backend;

        fn simple_network() -> LayerConfig {
            let mut net_cfg = SequentialConfig::default();
            net_cfg.add_input("data", &vec![1, 1, 28, 28]);
            net_cfg.add_layer(LayerConfig::new("linear", LayerType::Linear(LinearConfig { output_size: 10 })));

            LayerConfig::new("network", net_cfg)
        }

        #[test]
        fn save_and_load_layer() {
            let cfg = simple_network();
            let mut original_layer = Layer::from_config(native_backend(), &cfg);

            original_layer.save("target/testnetwork").unwrap();
            let mut loaded_layer = Layer::<Backend<Native>>::load(native_backend(), "target/testnetwork").unwrap();

            assert_eq!(original_layer.input_blob_names(), loaded_layer.input_blob_names());

            let original_weights = original_layer.learnable_weights_data();
            let original_weight_lock = original_weights[0].read().unwrap();
            let loaded_weights = loaded_layer.learnable_weights_data();
            let loaded_weight_lock = loaded_weights[0].read().unwrap();

            let original_weight = original_weight_lock.read(native_backend().device())
                .unwrap().as_native().unwrap().as_slice::<f32>();
            let loaded_weight = loaded_weight_lock.read(native_backend().device())
                .unwrap().as_native().unwrap().as_slice::<f32>();

            assert_eq!(original_weight, loaded_weight);
        }
    }

    #[cfg(feature="cuda")]
    mod cuda {
        use std::sync::{Arc, RwLock};
        use co::prelude::*;
        use leaf::layer::*;
        use leaf::layers::*;
        use leaf::util::write_to_memory;
        use super::{native_backend, cuda_backend};

        #[test]
        fn new_layer() {
            let cfg = super::new_layer_config();
            Layer::from_config(cuda_backend(), &cfg);
        }

        #[test]
        fn can_create_empty_sequential_layer() {
            let model = SequentialConfig::default();
            Layer::from_config(cuda_backend(), &LayerConfig::new("model", LayerType::Sequential(model)));
        }

        #[test]
        fn can_create_single_layer_sequential_layer() {
            let mut model = SequentialConfig::default();
            model.add_input("data", &[28, 28]);
            model.add_layer(LayerConfig::new("sigmoid", LayerType::Sigmoid));

            Layer::from_config(cuda_backend(), &LayerConfig::new("model", LayerType::Sequential(model)));
        }

        #[test]
        fn can_create_simple_network_sequential_layer() {
            let mut model = SequentialConfig::default();
            model.add_input("data", &[1, 784]);
            model.add_layer(LayerConfig::new("linear1", LinearConfig { output_size: 1568 }));
            model.add_layer(LayerConfig::new("sigmoid", LayerType::Sigmoid));
            model.add_layer(LayerConfig::new("linear2", LinearConfig { output_size: 10 }));

            let _ = Layer::from_config(cuda_backend(), &LayerConfig::new("model", LayerType::Sequential(model)));
        }

        #[test]
        fn reshape_does_not_affect_output() {
            let native_backend = native_backend();
            let cuda_backend = cuda_backend();

            let mut normal_model = SequentialConfig::default();
            normal_model.add_input("data", &[3]);
            normal_model.add_layer(LayerConfig::new("sigmoid", LayerType::Sigmoid));
            let mut normal_network = Layer::from_config(cuda_backend.clone(), &LayerConfig::new("normal_model", LayerType::Sequential(normal_model)));

            let mut reshape_model = SequentialConfig::default();
            reshape_model.add_input("data", &[3]);
            reshape_model.add_layer(LayerConfig::new("reshape", ReshapeConfig { shape: vec![1, 1, 3] }));
            reshape_model.add_layer(LayerConfig::new("sigmoid", LayerType::Sigmoid));
            let mut reshape_network = Layer::from_config(cuda_backend.clone(), &LayerConfig::new("reshape_model", LayerType::Sequential(reshape_model)));

            let input = vec![1f32, 1f32, 2f32];
            let mut normal_tensor = SharedTensor::<f32>::new(&[3]);
            // let mut normal_tensor_output = SharedTensor::<f32>::new(native_backend.device(), &(3)).unwrap();
            let mut reshape_tensor = SharedTensor::<f32>::new(&[3]);
            // let mut reshape_tensor_output = SharedTensor::<f32>::new(native_backend.device(), &(3)).unwrap();
            write_to_memory(normal_tensor.write_only(native_backend.device()).unwrap(), &input);
            write_to_memory(reshape_tensor.write_only(native_backend.device()).unwrap(), &input);

            let normal_tensor_output = normal_network.forward(&[Arc::new(RwLock::new(normal_tensor))])[0].clone();
            let normal_tensor_output_native_ = normal_tensor_output.read().unwrap();
            let normal_tensor_output_native = normal_tensor_output_native_
                .read(native_backend.device()).unwrap().as_native().unwrap();
            assert_eq!(&[0.7310585786f32, 0.7310586f32, 0.880797f32],
                       normal_tensor_output_native.as_slice::<f32>());

            let reshape_tensor_output = reshape_network.forward(&[Arc::new(RwLock::new(reshape_tensor))])[0].clone();
            let reshape_tensor_output_native_ = reshape_tensor_output.read().unwrap();
            let reshape_tensor_output_native = reshape_tensor_output_native_
                .read(native_backend.device()).unwrap().as_native().unwrap();
            assert_eq!(&[0.7310585786f32, 0.7310586f32, 0.880797f32],
                       reshape_tensor_output_native.as_slice::<f32>());
            assert_eq!(normal_tensor_output_native.as_slice::<f32>(),
                       reshape_tensor_output_native.as_slice::<f32>());
        }
    }

    // #[test]
    // fn dim_check_strict() {
    //     let cfg = WeightConfig { share_mode: DimCheckMode::Strict, ..WeightConfig::default() };
    //     let blob_one = SharedTensor::<f32>::new(backend().device(), &vec![2, 3, 3]);
    //     let blob_two = SharedTensor::<f32>::new(backend().device(), &vec![3, 2, 3]);
    //     let param_name = "foo".to_owned();
    //     let owner_name = "owner".to_owned();
    //     let layer_name = "layer".to_owned();
    //
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_one,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_ok());
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_two,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_err());
    // }

    // #[test]
    // fn dim_check_permissive() {
    //     let cfg = WeightConfig { share_mode: DimCheckMode::Permissive, ..WeightConfig::default() };
    //     let blob_one = SharedTensor::<f32>::new(backend().device(), &vec![2, 3, 3]);
    //     let blob_two = SharedTensor::<f32>::new(backend().device(), &vec![3, 2, 3]);
    //     let blob_three = SharedTensor::<f32>::new(backend().device(), &vec![3, 10, 3]);
    //     let param_name = "foo".to_owned();
    //     let owner_name = "owner".to_owned();
    //     let layer_name = "layer".to_owned();
    //
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_one,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_ok());
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_two,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_ok());
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_three,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_err());
    //     assert!(cfg.check_dimensions(&blob_two,
    //                                  &blob_three,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_err());
    // }
}
<commit_msg>test/layer_spec.rs: add a simple xor test<commit_after>extern crate leaf;
extern crate collenchyma as co;

#[cfg(test)]
mod layer_spec {
    use std::rc::Rc;
    use co::prelude::*;
    use leaf::layer::*;

    fn new_layer_config() -> LayerConfig {
        LayerConfig::new("foo", LayerType::Sigmoid)
    }

    fn native_backend() -> Rc<Backend<Native>> {
        Rc::new(Backend::<Native>::default().unwrap())
    }

    #[cfg(feature="cuda")]
    fn cuda_backend() -> Rc<Backend<Cuda>> {
        Rc::new(Backend::<Cuda>::default().unwrap())
    }

    #[cfg(all(feature="native", feature="cuda"))]
    mod native_cuda {
        use leaf::layer::*;
        use leaf::layers::*;
        use super::{native_backend, cuda_backend};

        #[test]
        fn create_layer_with_either() {
            let cfg = super::new_layer_config();
            Layer::from_config(native_backend(), &cfg);

            let cfg = super::new_layer_config();
            Layer::from_config(cuda_backend(), &cfg);
        }
    }

    #[cfg(feature="native")]
    mod native {
        use co::prelude::*;
        use leaf::layer::*;
        use leaf::layers::*;
        use super::native_backend;

        fn simple_network() -> LayerConfig {
            let mut net_cfg = SequentialConfig::default();
            net_cfg.add_input("data", &vec![1, 1, 28, 28]);
            net_cfg.add_layer(LayerConfig::new("linear", LayerType::Linear(LinearConfig { output_size: 10 })));

            LayerConfig::new("network", net_cfg)
        }

	#[test]
	fn xor_forward() {
		// let _ = env_logger::init();
		let mut cfg = SequentialConfig::default();
		// Layer: data
		cfg.add_input("data", &[2]);
		// Layer: fc1
		let fc1_layer_cfg = LinearConfig { output_size: 2 };
		let mut fc1_cfg = LayerConfig::new("fc1", LayerType::Linear(fc1_layer_cfg));
		fc1_cfg.add_input("data");
		fc1_cfg.add_output("fc1_out");
		cfg.add_layer(fc1_cfg);
		// Layer: fc2/output
		let fc2_layer_cfg = LinearConfig { output_size: 1 };
		let mut fc2_cfg = LayerConfig::new("fc2", LayerType::Linear(fc2_layer_cfg));
		fc2_cfg.add_input("fc1_out");
		fc2_cfg.add_output("fc2_out");
		cfg.add_layer(fc2_cfg);

		let backend = native_backend();
		let mut network = Layer::from_config(
		    backend.clone(), &LayerConfig::new("network", LayerType::Sequential(cfg)));
	}

        #[test]
        fn save_and_load_layer() {
            let cfg = simple_network();
            let mut original_layer = Layer::from_config(native_backend(), &cfg);

            original_layer.save("target/testnetwork").unwrap();
            let mut loaded_layer = Layer::<Backend<Native>>::load(native_backend(), "target/testnetwork").unwrap();

            assert_eq!(original_layer.input_blob_names(), loaded_layer.input_blob_names());

            let original_weights = original_layer.learnable_weights_data();
            let original_weight_lock = original_weights[0].read().unwrap();
            let loaded_weights = loaded_layer.learnable_weights_data();
            let loaded_weight_lock = loaded_weights[0].read().unwrap();

            let original_weight = original_weight_lock.read(native_backend().device())
                .unwrap().as_native().unwrap().as_slice::<f32>();
            let loaded_weight = loaded_weight_lock.read(native_backend().device())
                .unwrap().as_native().unwrap().as_slice::<f32>();

            assert_eq!(original_weight, loaded_weight);
        }
    }

    #[cfg(feature="cuda")]
    mod cuda {
        use std::sync::{Arc, RwLock};
        use co::prelude::*;
        use leaf::layer::*;
        use leaf::layers::*;
        use leaf::util::write_to_memory;
        use super::{native_backend, cuda_backend};

        #[test]
        fn new_layer() {
            let cfg = super::new_layer_config();
            Layer::from_config(cuda_backend(), &cfg);
        }

        #[test]
        fn can_create_empty_sequential_layer() {
            let model = SequentialConfig::default();
            Layer::from_config(cuda_backend(), &LayerConfig::new("model", LayerType::Sequential(model)));
        }

        #[test]
        fn can_create_single_layer_sequential_layer() {
            let mut model = SequentialConfig::default();
            model.add_input("data", &[28, 28]);
            model.add_layer(LayerConfig::new("sigmoid", LayerType::Sigmoid));

            Layer::from_config(cuda_backend(), &LayerConfig::new("model", LayerType::Sequential(model)));
        }

        #[test]
        fn can_create_simple_network_sequential_layer() {
            let mut model = SequentialConfig::default();
            model.add_input("data", &[1, 784]);
            model.add_layer(LayerConfig::new("linear1", LinearConfig { output_size: 1568 }));
            model.add_layer(LayerConfig::new("sigmoid", LayerType::Sigmoid));
            model.add_layer(LayerConfig::new("linear2", LinearConfig { output_size: 10 }));

            let _ = Layer::from_config(cuda_backend(), &LayerConfig::new("model", LayerType::Sequential(model)));
        }

        #[test]
        fn reshape_does_not_affect_output() {
            let native_backend = native_backend();
            let cuda_backend = cuda_backend();

            let mut normal_model = SequentialConfig::default();
            normal_model.add_input("data", &[3]);
            normal_model.add_layer(LayerConfig::new("sigmoid", LayerType::Sigmoid));
            let mut normal_network = Layer::from_config(cuda_backend.clone(), &LayerConfig::new("normal_model", LayerType::Sequential(normal_model)));

            let mut reshape_model = SequentialConfig::default();
            reshape_model.add_input("data", &[3]);
            reshape_model.add_layer(LayerConfig::new("reshape", ReshapeConfig { shape: vec![1, 1, 3] }));
            reshape_model.add_layer(LayerConfig::new("sigmoid", LayerType::Sigmoid));
            let mut reshape_network = Layer::from_config(cuda_backend.clone(), &LayerConfig::new("reshape_model", LayerType::Sequential(reshape_model)));

            let input = vec![1f32, 1f32, 2f32];
            let mut normal_tensor = SharedTensor::<f32>::new(&[3]);
            // let mut normal_tensor_output = SharedTensor::<f32>::new(native_backend.device(), &(3)).unwrap();
            let mut reshape_tensor = SharedTensor::<f32>::new(&[3]);
            // let mut reshape_tensor_output = SharedTensor::<f32>::new(native_backend.device(), &(3)).unwrap();
            write_to_memory(normal_tensor.write_only(native_backend.device()).unwrap(), &input);
            write_to_memory(reshape_tensor.write_only(native_backend.device()).unwrap(), &input);

            let normal_tensor_output = normal_network.forward(&[Arc::new(RwLock::new(normal_tensor))])[0].clone();
            let normal_tensor_output_native_ = normal_tensor_output.read().unwrap();
            let normal_tensor_output_native = normal_tensor_output_native_
                .read(native_backend.device()).unwrap().as_native().unwrap();
            assert_eq!(&[0.7310585786f32, 0.7310586f32, 0.880797f32],
                       normal_tensor_output_native.as_slice::<f32>());

            let reshape_tensor_output = reshape_network.forward(&[Arc::new(RwLock::new(reshape_tensor))])[0].clone();
            let reshape_tensor_output_native_ = reshape_tensor_output.read().unwrap();
            let reshape_tensor_output_native = reshape_tensor_output_native_
                .read(native_backend.device()).unwrap().as_native().unwrap();
            assert_eq!(&[0.7310585786f32, 0.7310586f32, 0.880797f32],
                       reshape_tensor_output_native.as_slice::<f32>());
            assert_eq!(normal_tensor_output_native.as_slice::<f32>(),
                       reshape_tensor_output_native.as_slice::<f32>());
        }
    }

    // #[test]
    // fn dim_check_strict() {
    //     let cfg = WeightConfig { share_mode: DimCheckMode::Strict, ..WeightConfig::default() };
    //     let blob_one = SharedTensor::<f32>::new(backend().device(), &vec![2, 3, 3]);
    //     let blob_two = SharedTensor::<f32>::new(backend().device(), &vec![3, 2, 3]);
    //     let param_name = "foo".to_owned();
    //     let owner_name = "owner".to_owned();
    //     let layer_name = "layer".to_owned();
    //
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_one,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_ok());
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_two,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_err());
    // }

    // #[test]
    // fn dim_check_permissive() {
    //     let cfg = WeightConfig { share_mode: DimCheckMode::Permissive, ..WeightConfig::default() };
    //     let blob_one = SharedTensor::<f32>::new(backend().device(), &vec![2, 3, 3]);
    //     let blob_two = SharedTensor::<f32>::new(backend().device(), &vec![3, 2, 3]);
    //     let blob_three = SharedTensor::<f32>::new(backend().device(), &vec![3, 10, 3]);
    //     let param_name = "foo".to_owned();
    //     let owner_name = "owner".to_owned();
    //     let layer_name = "layer".to_owned();
    //
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_one,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_ok());
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_two,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_ok());
    //     assert!(cfg.check_dimensions(&blob_one,
    //                                  &blob_three,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_err());
    //     assert!(cfg.check_dimensions(&blob_two,
    //                                  &blob_three,
    //                                  param_name.clone(),
    //                                  owner_name.clone(),
    //                                  layer_name.clone())
    //                .is_err());
    // }
}
<|endoftext|>


<commit_before>// compile-flags:-Zborrowck=mir

#![feature(member_constraints)]
#![feature(type_alias_impl_trait)]

#[derive(Clone)]
struct CopyIfEq<T, U>(T, U);

impl<T: Copy> Copy for CopyIfEq<T, T> {}

type E<'a, 'b> = impl Sized;

fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
    //~^ ERROR lifetime may not live long enough
    let v = CopyIfEq::<*mut _, *mut _>(&mut {x}, &mut y);
    let u = v;
    let _: *mut &'a i32 = u.1;
    unsafe { let _: &'b i32 = *u.0; }
    u.0
}

fn main() {}
<commit_msg>Explain a test<commit_after>// compile-flags:-Zborrowck=mir

#![feature(member_constraints)]
#![feature(type_alias_impl_trait)]

#[derive(Clone)]
struct CopyIfEq<T, U>(T, U);

impl<T: Copy> Copy for CopyIfEq<T, T> {}

type E<'a, 'b> = impl Sized;

fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
    //~^ ERROR lifetime may not live long enough
    let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y);

    // This assignment requires that `x` and `y` have the same type due to the
    // `Copy` impl. The reason why we are using a copy to create a constraint
    // is that only borrow checking (not regionck in type checking) enforces
    // this bound.
    let u = v;
    let _: *mut &'a i32 = u.1;
    unsafe {
        let _: &'b i32 = *u.0;
    }
    u.0
}

fn main() {}
<|endoftext|>


<commit_before>// TL;DR don't mem::swap the tables
// it's unsafe
extern crate toml_edit;

use toml_edit::{Document, Key};
use std::mem;

macro_rules! parse_doc {
    ($toml:ident) => (
        {
            let doc = $toml.parse::<Document>();
            assert!(doc.is_ok());
            doc.unwrap()
        }
    );
}

macro_rules! as_table {
    ($entry:ident) => (
        {
            assert!($entry.is_table());
            $entry.as_table_mut().unwrap()
        }
    );
}

macro_rules! parse_key {
    ($s:expr) => ($s.parse::<Key>().unwrap());
}

#[test]
fn test_safety_issue() {

    let toml1 = r#"
[a]
b = 2
[a.c]
b = 3
[d]
"#;
    let toml2 = r#"
[b]
a = 2
[b.c]
a = 3
[d]
"#;
    let mut doc1 = parse_doc!(toml1);
    let mut doc2 = parse_doc!(toml2);

    {
        let mut r1 = doc1.root_mut();
        let mut r2 = doc2.root_mut();
        {
            let mut a = r1.entry("a");
            let mut a = as_table!(a);
            let mut ac = a.entry("c");
            let mut ac = as_table!(ac);
            ac.insert_table(parse_key!("ac"));

            let mut b = r2.entry("b");
            let mut b = as_table!(b);
            let mut bc = b.entry("c");
            let mut bc = as_table!(bc);
            bc.insert_table(parse_key!("bc"));

            mem::swap(ac, bc); // now both documents are invalid (duplicate keys) :(
        }

        // what's even worse,
        // `a.c` is now pointing to `[b.c]`
        let mut a = r1.entry("a");
        let mut a = as_table!(a);
        let mut ac = a.entry("c");
        let mut ac = as_table!(ac);
        ac.insert_table(parse_key!("'i am in [b.c]'"));

        // same for `b.c`
        let mut b = r2.entry("b");
        let mut b = as_table!(b);
        let mut bc = b.entry("c");
        let mut bc = as_table!(bc);
        bc.insert_table(parse_key!("'i am in [a.c]'"));
    }

    assert_eq!(
        doc1.to_string(),
        r#"
[a]
b = 2
[b.c]
a = 3

[b.c.bc]

[b.c.'i am in [b.c]']
[d]
"#
    );
    assert_eq!(
        doc2.to_string(),
        r#"
[b]
a = 2
[a.c]
b = 3

[a.c.ac]

[a.c.'i am in [a.c]']
[d]
"#
    );
}
<commit_msg>test(safety): make test more interesting<commit_after>// TL;DR don't mem::swap the tables
// it's unsafe
extern crate toml_edit;

use toml_edit::{Document, Key};
use std::mem;

macro_rules! parse_doc {
    ($toml:ident) => (
        {
            let doc = $toml.parse::<Document>();
            assert!(doc.is_ok());
            doc.unwrap()
        }
    );
}

macro_rules! as_table {
    ($entry:ident) => (
        {
            assert!($entry.is_table());
            $entry.as_table_mut().unwrap()
        }
    );
}

macro_rules! parse_key {
    ($s:expr) => ($s.parse::<Key>().unwrap());
}

#[test]
fn test_safety_issue() {

    let toml1 = r#"
[a]
b = 2
[a.c]
b = 3
[d]
"#;
    let toml2 = r#"
[b.c]
a = 3
[b]
a = 2
[e]
"#;
    let mut doc1 = parse_doc!(toml1);
    let mut doc2 = parse_doc!(toml2);

    {
        let mut r1 = doc1.root_mut();
        let mut r2 = doc2.root_mut();
        {
            let mut a = r1.entry("a");
            let mut a = as_table!(a);
            let mut ac = a.entry("c");
            let mut ac = as_table!(ac);
            ac.insert_table(parse_key!("ac"));

            let mut b = r2.entry("b");
            let mut b = as_table!(b);
            let mut bc = b.entry("c");
            let mut bc = as_table!(bc);
            bc.insert_table(parse_key!("bc"));

            mem::swap(ac, bc); // now both documents are invalid (duplicate keys) :(
        }

        // what's even worse,
        // `a.c` is now pointing to `[b.c]`
        // also, the trailing tables list is swapped
        let mut a = r1.entry("a");
        let mut a = as_table!(a);
        let mut ac = a.entry("c");
        let mut ac = as_table!(ac);
        ac.insert_table(parse_key!("'i am in [b.c]'"));

        // same for `b.c`
        let mut b = r2.entry("b");
        let mut b = as_table!(b);
        let mut bc = b.entry("c");
        let mut bc = as_table!(bc);
        bc.insert_table(parse_key!("'i am in [a.c]'"));
    }

    assert_eq!(
        doc1.to_string(),
        r#"
[a]
b = 2

[b.c]
a = 3

[b.c.bc]

[b.c.'i am in [b.c]']
[b]
a = 2
[e]
"#
    );
    assert_eq!(
        doc2.to_string(),
        r#"[a.c]
b = 3

[a.c.ac]

[a.c.'i am in [a.c]']
[d]
"#
    );
}
<|endoftext|>


<commit_before>extern crate sunrise;
#[macro_use]
extern crate clap;
use clap::{Arg, App, SubCommand};

extern crate chrono;
use chrono::prelude::DateTime;
use chrono::{Utc, Local};
use std::time::{SystemTime, UNIX_EPOCH, Duration};
use std::convert::TryInto;

fn main() {
    let matches = App::new("sunrise-exe")
                          .version("1.0")
                          .about("prints out sunrise and sunset time")
                          .args_from_usage(
                              "-c, --config=[FILE] 'Sets a custom config file'
                              <INPUT>              'Sets the input file to use'
                              -v...                'Sets the level of verbosity'")
                          .subcommand(SubCommand::with_name("test")
                                      .about("controls testing features")
                                      .version("1.3")
                                      .author("Someone E. <someone_else@other.com>")
                                      .arg_from_usage("-d, --debug 'Print debug information'"))
                          .get_matches();

    // Gets a value for config if supplied by user, or defaults to "default.conf"
    let config = matches.value_of("config").unwrap_or("default.conf");
    println!("Value for config: {}", config);

    // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't
    // required we could have used an 'if let' to conditionally get the value)
    println!("Using input file: {}", matches.value_of("INPUT").unwrap());

    // Vary the output based on how many times the user used the "verbose" flag
    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
    match matches.occurrences_of("v") {
        0 => println!("No verbose info"),
        1 => println!("Some verbose info"),
        2 => println!("Tons of verbose info"),
        3 | _ => println!("Don't be crazy"),
    }

    // You can handle information about subcommands by requesting their matches by name
    // (as below), requesting just the name used, or both at the same time
    if let Some(matches) = matches.subcommand_matches("test") {
        if matches.is_present("debug") {
            println!("Printing debug info...");
        } else {
            println!("Printing normally...");
        }
    }

    // Calculate times for December 11, 2021 in Moscow
    let (sunrise, sunset) = sunrise::sunrise_sunset(
        55.4544,
        37.3763,
        2021,
        12,
        11,
    );
    println!("sunrise: {} sunset: {}", sunrise, sunset);

    // https://stackoverflow.com/questions/50072055/converting-unix-timestamp-to-readable-time-string-in-rust

    // Creates a new SystemTime from the specified number of whole seconds
    let d = UNIX_EPOCH + Duration::from_secs(sunrise.try_into().unwrap());
    // Create DateTime from SystemTime
    //let datetime = DateTime::<Utc>::from(d);
    let datetime = DateTime::<Local>::from(d);
    // Formats the combined date and time with the specified format string.
    let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string();
    println!{"{}",timestamp_str};

}
<commit_msg>finished sunrise sample<commit_after>extern crate sunrise;
#[macro_use]
extern crate clap;
use clap::{Arg, App, SubCommand};

extern crate chrono;
use chrono::prelude::{DateTime};
use chrono::{Utc, Local, NaiveDate, Datelike};
use std::time::{SystemTime, UNIX_EPOCH, Duration};
use std::convert::TryInto;

fn timestamp_to_time(timestamp: i64) -> String {
    // https://stackoverflow.com/questions/50072055/converting-unix-timestamp-to-readable-time-string-in-rust

    // Creates a new SystemTime from the specified number of whole seconds
    let d = UNIX_EPOCH + Duration::from_secs(timestamp.try_into().unwrap());
    // Create DateTime from SystemTime
    //let datetime = DateTime::<Utc>::from(d);
    let datetime = DateTime::<Local>::from(d);
    // Formats the combined date and time with the specified format string.
    //let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string();
    let timestamp_str = datetime.format("%H:%M:%S").to_string();
    timestamp_str
}

fn main() {
    let matches = App::new("sunrise-exe")
                          .version("1.0")
                          .about("prints out sunrise and sunset time")
                          .args_from_usage(
                              "-c, --config=[FILE]        'Sets a custom config file'
                              -l, --longitude=[LONGITUDE] 'Sets the place longitude'
                              -t, --latitude=[LATITUDE]   'Sets the place latitude'
                              -d, --date=[DATE]           'Sets the date in local timezone'
                              -v...                       'Sets the level of verbosity'")
                          .subcommand(SubCommand::with_name("test")
                                      .about("controls testing features")
                                      .version("1.3")
                                      .author("Someone E. <someone_else@other.com>")
                                      .arg_from_usage("-d, --debug 'Print debug information'"))
                          .get_matches();

    // Vary the output based on how many times the user used the "verbose" flag
    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
    let verbosity_level = matches.occurrences_of("v");

    // Gets a value for config if supplied by user, or defaults to "default.conf"
    let config = matches.value_of("config").unwrap_or("default.conf");
    if verbosity_level >= 2 {
        println!("Value for config: {}", config);
    }

    let longitude_str = matches.value_of("longitude").unwrap_or("55.4544");
    let latitude_str = matches.value_of("latitude").unwrap_or("37.3763");

    let longitude = longitude_str.parse::<f64>().unwrap();
    let latitude = latitude_str.parse::<f64>().unwrap();
    if verbosity_level >= 2 {
        println!("longitude {} latitude {}", longitude, latitude);
    }

    // https://stackoverflow.com/questions/61179070/rust-chrono-parse-date-string-parseerrornotenough-and-parseerrortooshort
    let date_str = matches.value_of("date").unwrap_or("1970-01-01");
    if verbosity_level >= 3 {
        println!("Value for date: {}", date_str);
    }
    let naive_date = NaiveDate::parse_from_str(date_str, "%Y-%m-%d").unwrap();
    if verbosity_level >= 1 {
        println!("Parsed date: {:?} {} {} {}",
            &naive_date, naive_date.year(), naive_date.month(), naive_date.day());
    }

    // You can handle information about subcommands by requesting their matches by name
    // (as below), requesting just the name used, or both at the same time
    if let Some(matches) = matches.subcommand_matches("test") {
        if matches.is_present("debug") {
            println!("Printing debug info...");
        } else {
            println!("Printing normally...");
        }
    }

    // Calculate times for December 11, 2021 in Moscow
    let (sunrise, sunset) = sunrise::sunrise_sunset(
        longitude,          // 55.4544,
        latitude,           // 37.3763,
        naive_date.year(),  // 2021,
        naive_date.month(), // 12,
        naive_date.day(),   // 11,
    );
    if verbosity_level >= 3 {
        println!("sunrise: {} sunset: {}", sunrise, sunset);
    }

    let sunrise_str = timestamp_to_time(sunrise);
    let sunset_str = timestamp_to_time(sunset);

    println!{"sunrize {} and sunset {} at {:?} for ({} {})",
        sunrise_str, sunset_str, &naive_date, longitude, latitude};

}
<|endoftext|>


<commit_before>extern crate std;

use model::ComCrate;
use syn;

/// Detailed information of a Rust type.
pub enum RustType<'e>
{
    Ident( &'e syn::Ident ),
    Void,
}

/// Defines how a value is passed to/from Rust function.
#[derive(PartialEq, PartialOrd, Clone)]
pub enum PassBy
{
    Value,

    Reference,

    Ptr,
}

/// Details of a Rust type. Used for translation to other programming languages.
pub struct TypeInfo<'s>
{
    /// The crate this type is associated with.
    pub krate: &'s ComCrate,

    /// The type in rust.
    pub rust_type: RustType<'s>,

    /// Specifies how the value is passed to/from a function. Default: PassBy::Value
    pub pass_by: PassBy,

    /// Is the Rust type defined as mutable? Default: false
    pub is_mutable: bool,

    /// The length of the array if the Rust type denotes an array.
    pub array_length: Option<&'s syn::Expr>
}

pub trait ForeignTypeHandler
{
    /// Gets the name for the 'ty'.
    fn get_name( &self, krate : &ComCrate, ty : &syn::Ident ) -> String;

    /// Gets the COM type for a Rust type.
    fn get_ty<'a, 'b: 'a>( &self, krate : &'b ComCrate, ty : &'b syn::Type ) -> Option< TypeInfo<'a> >;
}

pub struct CTypeHandler;

/// Collects details of a Rust type when the Rust crate is parsed.
struct TypeInfoResolver<'s>
{
    /// The crate this type is associated with.
    krate: &'s ComCrate,

    /// The type in rust.
    rust_type: RustType<'s>,

    /// Specifies how the value is passed. Default: PassBy::Value
    pass_by: Option<PassBy>,

    /// Is the Rust type defined as mutable? Default: false
    is_mutable: Option<bool>,

    /// The length of the array if the Rust type denotes an array.
    array_length: Option<&'s syn::Expr>
}

impl ForeignTypeHandler for CTypeHandler
{
    /// Tries to apply renaming to the name.
    fn get_name(
        &self,
        krate: &ComCrate,
        ident: &syn::Ident,
    ) -> String
    {
        self.get_name_for_ty( krate, ident.as_ref() )
    }

    fn get_ty<'a, 'b: 'a>(
        &self,
        krate: &'b ComCrate,
        ty: &'b syn::Type,
    ) -> Option<TypeInfo<'a>>
    {
        match TypeInfoResolver::from_type( krate, ty )
        {
            Some( resolver ) => Some( TypeInfo::from_resolver( resolver ) ),
            None => None,
        }
    }
}

impl<'s, 'p: 's> TypeInfo<'s> {

    /// Gets the name of the type in Rust.
    pub fn get_name(
        &self
    ) -> String
    {
        format!( "{}", self.rust_type )
    }

    /// Initializes the type info from resolver which has resolved the type.
    fn from_resolver(
        resolver: TypeInfoResolver<'p>
    ) -> TypeInfo<'s>
    {
        // Resolve default values.
        // NOTE: The existence of the array length value identifies an array type and
        // is therefor passed as-is here.
        let pass_by;
        let is_mutable;
        {
            pass_by = match resolver.pass_by {
                Some( ref v ) => v,
                None => &PassBy::Value,
            };

            is_mutable = match resolver.is_mutable {
                Some( ref v ) => v.clone(),
                None => false,
            };
        };

        TypeInfo{
            krate: resolver.krate,
            rust_type: resolver.rust_type,
            pass_by: pass_by.clone(),
            is_mutable: is_mutable,
            array_length: resolver.array_length,
        }
    }
}

impl<'s> std::fmt::Display for RustType<'s> {

    fn fmt(
        &self,
        f: &mut std::fmt::Formatter
    ) -> std::fmt::Result {
        match self {
            &RustType::Ident( syn_ident ) => write!( f, "{}", syn_ident ),
            &RustType::Void => write!( f, "void" ),
        }
    }
}

impl<'s, 'p: 's> TypeInfoResolver<'s> {

    /// Parses the type info from the specified Type.
    fn from_type(
        krate: &'p ComCrate,
        syn_type: &'p syn::Type,
    ) -> Option<TypeInfoResolver<'s>>
    {
        match *syn_type {

            // Delegate to appropriate conversion.
            syn::Type::Slice( ref slice ) => TypeInfoResolver::from_slice( krate, slice ),
            syn::Type::Reference( ref reference ) => TypeInfoResolver::from_reference( krate, reference ),
            syn::Type::Ptr( ref ptr ) => TypeInfoResolver::from_pointer( krate, ptr ),
            syn::Type::Array( ref arr ) => TypeInfoResolver::from_array( krate, arr ),
            syn::Type::Path( ref p ) => TypeInfoResolver::from_path( krate, p ),
            syn::Type::Tuple( ref t ) if t.elems.is_empty() => Some( TypeInfoResolver::void( krate ) ),

            syn::Type::BareFn(..)
                | syn::Type::Never(..)
                | syn::Type::Tuple(..)
                | syn::Type::TraitObject(..)
                | syn::Type::ImplTrait(..)
                | syn::Type::Paren(..)
                | syn::Type::Infer(..)
                | syn::Type::Macro(..)
                | syn::Type::Verbatim(..)
                | syn::Type::Group(..)
                => None,
        }
    }

    fn new(
        krate: &'p ComCrate,
        rust_type: RustType<'s>
    ) -> TypeInfoResolver<'s>
    {
        TypeInfoResolver {
            krate: krate,
            rust_type: rust_type,
            pass_by: None,
            is_mutable: None,
            array_length: None,
        }
    }

    fn void(
        krate: &'p ComCrate,
    ) -> TypeInfoResolver<'s>
    {
        TypeInfoResolver::new( krate, RustType::Void )
    }

    fn pass_by_option(
        resolver: Option<TypeInfoResolver<'s>>,
        pass_by: PassBy,
    ) -> Option<TypeInfoResolver<'s>>
    {
        match resolver {
            Some( r ) => Some( TypeInfoResolver::pass_by( r, pass_by ) ),
            None => None,
        }
    }

    fn pass_by(
        resolver: TypeInfoResolver<'s>,
        pass_by: PassBy,
    ) -> TypeInfoResolver<'s>
    {
        match resolver.pass_by {
            Some( _ ) => panic!("Cannot set pass_by twice."),
            None => {},
        }

        TypeInfoResolver {
            krate: resolver.krate,
            rust_type: resolver.rust_type,
            pass_by: Some( pass_by ),
            is_mutable: resolver.is_mutable,
            array_length: resolver.array_length,
        }
    }

    fn mutable_option(
        resolver: Option<TypeInfoResolver<'s>>,
        is_mutable: bool,
    ) -> Option<TypeInfoResolver<'s>>
    {
        match resolver {
            Some( r ) => Some( TypeInfoResolver::mutable( r, is_mutable ) ),
            None => None,
        }
    }

    fn mutable(
        resolver: TypeInfoResolver<'s>,
        is_mutable: bool,
    ) -> TypeInfoResolver<'s>
    {
        match resolver.is_mutable {
            Some(_) => panic!("Cannot set is_mutable twice."),
            None => {}
        }

        TypeInfoResolver {
            krate: resolver.krate,
            rust_type: resolver.rust_type,
            pass_by: resolver.pass_by,
            is_mutable: Some( is_mutable ),
            array_length: resolver.array_length,
        }
    }

    fn array_option(
        resolver: Option<TypeInfoResolver<'s>>,
        array_length: &'p syn::Expr,
    ) -> Option<TypeInfoResolver<'s>>
    {
        match resolver {
            Some( r ) => Some( TypeInfoResolver::array( r, array_length ) ),
            None => None,
        }
    }

    fn array(
        resolver: TypeInfoResolver<'s>,
        array_length: &'p syn::Expr,
    ) -> TypeInfoResolver<'s>
    {
        match resolver.array_length {
            Some(_) => panic!("Cannot set array_length twice."),
            None => {}
        }

        TypeInfoResolver {
            krate: resolver.krate,
            rust_type: resolver.rust_type,
            pass_by: resolver.pass_by,
            is_mutable: resolver.is_mutable,
            array_length: Some( array_length ),
        }
    }

    fn from_array(
        krate : &'p ComCrate,
        array: &'p syn::TypeArray,
    ) -> Option<TypeInfoResolver<'s>>
    {
        TypeInfoResolver::array_option(
            TypeInfoResolver::from_type( krate, &array.elem ),
            &array.len,
        )
    }

    fn from_slice(
        krate : &'p ComCrate,
        slice: &'p syn::TypeSlice,
    ) -> Option<TypeInfoResolver<'s>>
    {
        TypeInfoResolver::from_type( krate, &slice.elem )
    }

    fn from_reference(
        krate : &'p ComCrate,
        reference : &'p syn::TypeReference,
    ) -> Option<TypeInfoResolver<'s>>
    {
        TypeInfoResolver::pass_by_option(
                TypeInfoResolver::mutable_option(
                            TypeInfoResolver::from_type( krate, &reference.elem ),
                            TypeInfoResolver::is_mutable( &reference.mutability )
                        ),
                PassBy::Reference,
        )
    }

    fn from_pointer(
        krate : &'p ComCrate,
        ptr : &'p syn::TypePtr,
    ) -> Option<TypeInfoResolver<'s>>
    {
        TypeInfoResolver::pass_by_option(
            TypeInfoResolver::mutable_option(
                TypeInfoResolver::from_type( krate, &ptr.elem ),
                TypeInfoResolver::is_mutable( &ptr.mutability ),
            ),
            PassBy::Ptr,
        )
    }

    fn from_path(
        krate: &'p ComCrate,
        type_path: &'p syn::TypePath,
    ) -> Option<TypeInfoResolver<'s>>
    {
        TypeInfoResolver::from_segment( krate, type_path.path.segments.last().unwrap().value() )
    }

    fn from_segment(
        krate: &'p ComCrate,
        segment: &'p syn::PathSegment,
    ) -> Option<TypeInfoResolver<'s>>
    {
        // Get the segment as a string.
        let rust_type = format!( "{}", segment.ident );

        // Get the type information.
        let args = match segment.arguments {
            syn::PathArguments::None
                    => None,

            syn::PathArguments::AngleBracketed( ref data )
                    => Some( &data.args ),

            // Parenthesized path parameters should be valid only for Fn-types.
            // These types are unsupported, but we'll match for them here anyway.
            syn::PathArguments::Parenthesized( .. )
                    => panic!( "Fn-types are unsupported." ),
        };

        match rust_type.as_str() {

            // Extract a wrapped type.
            "ComRc" | "ComItf" | "ComResult"
                => TypeInfoResolver::pass_by_option( TypeInfoResolver::from_type(
                        krate,
                        match **args.unwrap().first().unwrap().value() {
                            syn::GenericArgument::Type( ref t ) => t,
                            _ => return None,
                        } ), PassBy::Ptr ),

            // Bare type.
            _t => Some( TypeInfoResolver::new( krate, RustType::Ident( &segment.ident ) ) ),
        }
    }

    /// Determines if the given type is mutable
    fn is_mutable(
        mutability: &Option<syn::token::Mut>
    ) -> bool
    {
        match mutability {
            &Some( _ ) => true,
            &None => false,
        }
    }
}

impl CTypeHandler
{
     fn get_name_for_ty(
        &self,
        krate : &ComCrate,
        ty_name : &str
    ) -> String
    {
        let itf = if let Some( itf ) = krate.interfaces().get( ty_name ) {
            itf
        } else {
            return ty_name.to_owned()
        };

        if itf.item_type() == ::utils::InterfaceType::Struct {
            format!( "I{}", itf.name() )
        } else {
            ty_name.to_owned()
        }
    }
}
<commit_msg>Simplified the logic in foreign_ty as noted in review<commit_after>extern crate std;

use model::ComCrate;
use syn;

/// Detailed information of a Rust type.
pub enum RustType<'e>
{
    Ident( &'e syn::Ident ),
    Void,
}

/// Defines how a value is passed to/from Rust function.
#[derive(PartialEq, PartialOrd, Clone, Copy)]
pub enum PassBy
{
    Value,

    Reference,

    Ptr,
}

/// Details of a Rust type. Used for translation to other programming languages.
pub struct TypeInfo<'s>
{
    /// The crate this type is associated with.
    pub krate: &'s ComCrate,

    /// The type in rust.
    pub rust_type: RustType<'s>,

    /// Specifies how the value is passed to/from a function. Default: PassBy::Value
    pub pass_by: PassBy,

    /// Is the Rust type defined as mutable? Default: false
    pub is_mutable: bool,

    /// The length of the array if the Rust type denotes an array.
    pub array_length: Option<&'s syn::Expr>
}

pub trait ForeignTypeHandler
{
    /// Gets the name for the 'ty'.
    fn get_name( &self, krate : &ComCrate, ty : &syn::Ident ) -> String;

    /// Gets the COM type for a Rust type.
    fn get_ty<'a, 'b: 'a>( &self, krate : &'b ComCrate, ty : &'b syn::Type ) -> Option< TypeInfo<'a> >;
}

pub struct CTypeHandler;

/// Collects details of a Rust type when the Rust crate is parsed.
struct TypeInfoResolver<'s>
{
    /// The crate this type is associated with.
    krate: &'s ComCrate,

    /// The type in rust.
    rust_type: RustType<'s>,

    /// Specifies how the value is passed. Default: PassBy::Value
    pass_by: Option<PassBy>,

    /// Is the Rust type defined as mutable? Default: false
    is_mutable: Option<bool>,

    /// The length of the array if the Rust type denotes an array.
    array_length: Option<&'s syn::Expr>
}

impl ForeignTypeHandler for CTypeHandler
{
    /// Tries to apply renaming to the name.
    fn get_name(
        &self,
        krate: &ComCrate,
        ident: &syn::Ident,
    ) -> String
    {
        self.get_name_for_ty( krate, ident.as_ref() )
    }

    fn get_ty<'a, 'b: 'a>(
        &self,
        krate: &'b ComCrate,
        ty: &'b syn::Type,
    ) -> Option<TypeInfo<'a>>
    {
        let resolver = TypeInfoResolver::from_type( krate, ty )?;

        Some( TypeInfo::from_resolver( resolver ) )
    }
}

impl<'s, 'p: 's> TypeInfo<'s> {

    /// Gets the name of the type in Rust.
    pub fn get_name(
        &self
    ) -> String
    {
        format!( "{}", self.rust_type )
    }

    /// Initializes the type info from resolver which has resolved the type.
    fn from_resolver(
        resolver: TypeInfoResolver<'p>
    ) -> TypeInfo<'s>
    {
        // Resolve default values.
        // NOTE: The existence of the array length value identifies an array type and
        // is therefor passed as-is here.
        let pass_by = resolver.pass_by.unwrap_or( PassBy::Value );
        let is_mutable = resolver.is_mutable.unwrap_or( false );

        TypeInfo{
            krate: resolver.krate,
            rust_type: resolver.rust_type,
            pass_by: pass_by,
            is_mutable: is_mutable,
            array_length: resolver.array_length,
        }
    }
}

impl<'s> std::fmt::Display for RustType<'s> {

    fn fmt(
        &self,
        f: &mut std::fmt::Formatter
    ) -> std::fmt::Result {
        match *self {
            RustType::Ident( syn_ident ) => write!( f, "{}", syn_ident ),
            RustType::Void => write!( f, "void" ),
        }
    }
}

impl<'s, 'p: 's> TypeInfoResolver<'s> {

    /// Parses the type info from the specified Type.
    fn from_type(
        krate: &'p ComCrate,
        syn_type: &'p syn::Type,
    ) -> Option<TypeInfoResolver<'s>>
    {
        match *syn_type {

            // Delegate to appropriate conversion.
            syn::Type::Slice( ref slice ) => TypeInfoResolver::from_slice( krate, slice ),
            syn::Type::Reference( ref reference ) => TypeInfoResolver::from_reference( krate, reference ),
            syn::Type::Ptr( ref ptr ) => TypeInfoResolver::from_pointer( krate, ptr ),
            syn::Type::Array( ref arr ) => TypeInfoResolver::from_array( krate, arr ),
            syn::Type::Path( ref p ) => TypeInfoResolver::from_path( krate, p ),
            syn::Type::Tuple( ref t ) if t.elems.is_empty() => Some( TypeInfoResolver::void( krate ) ),

            syn::Type::BareFn(..)
                | syn::Type::Never(..)
                | syn::Type::Tuple(..)
                | syn::Type::TraitObject(..)
                | syn::Type::ImplTrait(..)
                | syn::Type::Paren(..)
                | syn::Type::Infer(..)
                | syn::Type::Macro(..)
                | syn::Type::Verbatim(..)
                | syn::Type::Group(..)
                => None,
        }
    }

    fn new(
        krate: &'p ComCrate,
        rust_type: RustType<'s>
    ) -> TypeInfoResolver<'s>
    {
        TypeInfoResolver {
            krate: krate,
            rust_type: rust_type,
            pass_by: None,
            is_mutable: None,
            array_length: None,
        }
    }

    fn void(
        krate: &'p ComCrate,
    ) -> TypeInfoResolver<'s>
    {
        TypeInfoResolver::new( krate, RustType::Void )
    }

    fn pass_by(
        resolver: TypeInfoResolver<'s>,
        pass_by: PassBy,
    ) -> TypeInfoResolver<'s>
    {
        if resolver.pass_by.is_some() {
            panic!("Cannot set pass_by twice.")
        }

        TypeInfoResolver {
            krate: resolver.krate,
            rust_type: resolver.rust_type,
            pass_by: Some( pass_by ),
            is_mutable: resolver.is_mutable,
            array_length: resolver.array_length,
        }
    }

    fn mutable(
        resolver: TypeInfoResolver<'s>,
        is_mutable: bool,
    ) -> TypeInfoResolver<'s>
    {
        if resolver.is_mutable.is_some() {
            panic!("Cannot set is_mutable twice.")
        }

        TypeInfoResolver {
            krate: resolver.krate,
            rust_type: resolver.rust_type,
            pass_by: resolver.pass_by,
            is_mutable: Some( is_mutable ),
            array_length: resolver.array_length,
        }
    }

    fn array(
        resolver: TypeInfoResolver<'s>,
        array_length: &'p syn::Expr,
    ) -> TypeInfoResolver<'s>
    {
        if resolver.array_length.is_some() {
            panic!("Cannot set array_length twice.")
        }

        TypeInfoResolver {
            krate: resolver.krate,
            rust_type: resolver.rust_type,
            pass_by: resolver.pass_by,
            is_mutable: resolver.is_mutable,
            array_length: Some( array_length ),
        }
    }

    fn from_array(
        krate : &'p ComCrate,
        array: &'p syn::TypeArray,
    ) -> Option<TypeInfoResolver<'s>>
    {
        let resolver = TypeInfoResolver::from_type( krate, &array.elem )?;

        Some( TypeInfoResolver::array( resolver, &array.len ) )
    }

    fn from_slice(
        krate : &'p ComCrate,
        slice: &'p syn::TypeSlice,
    ) -> Option<TypeInfoResolver<'s>>
    {
        TypeInfoResolver::from_type( krate, &slice.elem )
    }

    fn from_reference(
        krate : &'p ComCrate,
        reference : &'p syn::TypeReference,
    ) -> Option<TypeInfoResolver<'s>>
    {
        let resolver = TypeInfoResolver::from_type( krate, &reference.elem )?;
        let resolver = TypeInfoResolver::mutable( resolver,
                TypeInfoResolver::is_mutable( &reference.mutability ) );

        Some( TypeInfoResolver::pass_by( resolver, PassBy::Reference ) )
    }

    fn from_pointer(
        krate : &'p ComCrate,
        ptr : &'p syn::TypePtr,
    ) -> Option<TypeInfoResolver<'s>>
    {
        let resolver = TypeInfoResolver::from_type( krate, &ptr.elem )?;
        let resolver = TypeInfoResolver::mutable( resolver,
                TypeInfoResolver::is_mutable( &ptr.mutability ) );

        Some( TypeInfoResolver::pass_by( resolver, PassBy::Ptr ) )
    }

    fn from_path(
        krate: &'p ComCrate,
        type_path: &'p syn::TypePath,
    ) -> Option<TypeInfoResolver<'s>>
    {
        TypeInfoResolver::from_segment( krate, type_path.path.segments.last().unwrap().value() )
    }

    fn from_segment(
        krate: &'p ComCrate,
        segment: &'p syn::PathSegment,
    ) -> Option<TypeInfoResolver<'s>>
    {
        // Get the segment as a string.
        let rust_type = format!( "{}", segment.ident );

        // Get the type information.
        let args = match segment.arguments {
            syn::PathArguments::None
                    => None,

            syn::PathArguments::AngleBracketed( ref data )
                    => Some( &data.args ),

            // Parenthesized path parameters should be valid only for Fn-types.
            // These types are unsupported, but we'll match for them here anyway.
            syn::PathArguments::Parenthesized( .. )
                    => panic!( "Fn-types are unsupported." ),
        };

        match rust_type.as_str() {

            // Extract a wrapped type.
            "ComRc" | "ComItf" | "ComResult"
                => Some( TypeInfoResolver::pass_by( TypeInfoResolver::from_type(
                        krate,
                        match **args.unwrap().first().unwrap().value() {
                            syn::GenericArgument::Type( ref t ) => t,
                            _ => return None,
                        } )?, PassBy::Ptr ) ),

            // Bare type.
            _t => Some( TypeInfoResolver::new( krate, RustType::Ident( &segment.ident ) ) ),
        }
    }

    /// Determines if the given type is mutable
    fn is_mutable(
        mutability: &Option<syn::token::Mut>
    ) -> bool
    {
        mutability.is_some()
    }
}

impl CTypeHandler
{
     fn get_name_for_ty(
        &self,
        krate : &ComCrate,
        ty_name : &str
    ) -> String
    {
        let itf = if let Some( itf ) = krate.interfaces().get( ty_name ) {
            itf
        } else {
            return ty_name.to_owned()
        };

        if itf.item_type() == ::utils::InterfaceType::Struct {
            format!( "I{}", itf.name() )
        } else {
            ty_name.to_owned()
        }
    }
}
<|endoftext|>


<commit_before>use std::str::{Chars};
use std::iter::Peekable;

use parser_combinators::primitives::{SourcePosition};
use unicode_segmentation::{UnicodeSegmentation, GraphemeIndices};

use super::token::{Token, TokenType};

#[derive(Clone)]
struct CodeIter<'a> {
    iter: GraphemeIndices<'a>,
    buf: Option<Peekable<Chars<'a>>>,
    grapheme: Option<&'a str>,
    offset: usize,
    line: i32,
    column: i32,
}

impl <'a> Iterator for CodeIter<'a> {
    type Item = (char, usize, i32, i32);

    fn next(&mut self) -> Option<(char, usize, i32, i32)> {
        if self.buf.is_none() {
            if self.peek().is_none() {
                return None;
            }
        }
        if let Some(ref mut buf) = self.buf {
            match buf.next() {
                Some(ch) => {
                    return Some((ch, self.offset, self.line, self.column));
                }
                None => {}
            }
        }
        self.buf = None;
        return self.next();
    }
}

impl <'a> CodeIter<'a> {
    fn peek(&mut self) -> Option<(char, usize, i32, i32)> {
        if let Some(ref mut buf) = self.buf {
            if let Some(ch) = buf.peek() {
                return Some((*ch, self.offset, self.line, self.column));
            }
        }
        if let Some(gr) = self.grapheme {
            if gr == "\n" {
                self.line += 1;
                self.column = 1;
            } else {
                self.column += 1;
            }
            self.offset += gr.as_bytes().len();
            self.buf = None;
            self.grapheme = None;
        }
        match self.iter.next() {
            Some((_, grapheme)) => {
                self.grapheme = Some(grapheme);
                self.buf = Some(grapheme.chars().peekable());
                self.peek()
            }
            None => None,
        }
    }
}

#[derive(Clone)]
pub struct Tokenizer<'a> {
    data: &'a str,
    iter: CodeIter<'a>,
    braces: Vec<char>,
    indents: Vec<usize>,
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Token<'a>;
    fn next(&mut self) -> Option<Token<'a>> {
        let tok = self._next();
        println!("Next token {:?}", tok);
        return tok;
    }
}

impl<'a> Tokenizer<'a> {
    pub fn new(val: &'a str) -> Tokenizer<'a> {
        return Tokenizer {
            data: val,
            iter: CodeIter {
                iter: UnicodeSegmentation::grapheme_indices(val, true),
                buf: None,
                grapheme: None,
                offset: 0,
                line: 1,
                column: 1,
                },
            braces: vec!(),
            indents: vec!(0),
        };
    }
    fn _next(&mut self) -> Option<Token<'a>> {
        'outer: loop {
            match self.iter.peek() {
                Some((ch, _, _, 1)) if ch != ' ' && self.indents.len() > 1 => {
                    let pos = SourcePosition {
                        line: self.iter.line,
                        column: self.iter.column,
                        };
                    return Some((TokenType::Dedent, "", pos));
                }
                _ => {}
            }
            match self.iter.next() {
                Some((ch, off, line, column)) => {
                    let pos = SourcePosition {
                        line: line,
                        column: column,
                        };
                    match ch {
                        '\n' => {
                            if column == 1 {
                                continue;  // skip empty line
                            }
                            return Some((TokenType::Newline, "\n", pos));
                        }
                        '('|'{'|'[' => {
                            let typ = match ch {
                                '(' => TokenType::OpenParen,
                                '{' => TokenType::OpenBrace,
                                '[' => TokenType::OpenBracket,
                                _ => unreachable!(),
                            };
                            self.braces.push(ch);
                            return Some((typ, &self.data[off..off+1], pos));
                        }
                        ')'|'}'|']' => {
                            let (typ, val) = match ch {
                                ')' => (TokenType::CloseParen, '('),
                                '}' => (TokenType::CloseBrace, '{'),
                                ']' => (TokenType::CloseBracket, '['),
                                _ => unreachable!(),
                            };
                            let br = self.braces.pop();
                            if Some(val) == br {
                                return Some((typ, &self.data[off..off+1], pos));
                            } else {
                                // TODO(tailhook) how to communicate error?
                                return None;
                            }
                        }
                        ':'|'.'|'='|'-'|',' => {
                            let typ = match ch {
                                ':' => TokenType::Colon,
                                '.' => TokenType::Dot,
                                '=' => TokenType::Equals,
                                '-' => TokenType::Dash,
                                ',' => TokenType::Comma,
                                _ => unreachable!(),
                            };
                            return Some((typ, &self.data[off..off+1], pos));
                        }
                        '#' => {
                            loop {
                                match self.iter.next() {
                                    Some(('\n', _, _, _)) | None => break,
                                    Some(_) => {}
                                }
                            }
                            continue;
                        }
                        '"'|'\'' => {
                            let dlm = ch;
                            loop {
                                match self.iter.next() {
                                    Some((ch, _, _, _)) if ch == dlm => {
                                        break;
                                    }
                                    Some(('\\', _, _, _)) => {
                                        // any char allowed after slash
                                        self.iter.next();
                                    }
                                    Some(_) => {}
                                    None => {
                                        // TODO(tailhook) return error
                                        break;
                                    }
                                }
                            }
                            let value = &self.data[off..self.iter.offset+1];
                            return Some((TokenType::String, value, pos));
                        }
                        ' ' if column == 1 => {
                            let mut offset;
                            let mut indent;
                            loop {
                                match self.iter.peek() {
                                    Some(('\n', _, _, _)) => {
                                        self.iter.next();  // skip empty line
                                        continue 'outer;
                                    }
                                    Some((' ', _, _, _)) => {
                                        self.iter.next();
                                        continue;
                                    }
                                    Some(('#', _, _, _)) => {
                                        continue 'outer;
                                    }
                                    Some((_, off, _, col)) => {
                                        offset = off;
                                        indent = (col - 1) as usize;
                                        break;
                                    }
                                    None => {
                                        continue 'outer;  // WS at EOF
                                    }
                                }
                            }
                            let chunk = &self.data[off..offset];
                            let mut typ;
                            let curindent = *self.indents.last().unwrap();
                            if indent == curindent {
                                continue;
                            } else if indent > curindent {
                                self.indents.push(indent);
                                typ = TokenType::Indent;
                            } else {
                                loop {
                                    let nindent = self.indents.pop().unwrap();
                                    if nindent == indent {
                                        self.indents.push(indent);
                                        break;
                                    } else if nindent < indent {
                                        // TODO(tailhook) how to report err?
                                        return None;
                                    }
                                }
                                typ = TokenType::Dedent;
                            }
                            return Some((typ, chunk, pos));
                        }
                        ' '|'\t' => {  // Skip whitespace
                            continue;
                        }
                        'a'...'z'|'A'...'Z'|'_' => {
                            let mut offset = self.data.len();
                            loop {
                                match self.iter.peek() {
                                    Some((x, off, _, _)) => {
                                        match x {
                                            'a'...'z'|'A'...'Z'|'0'...'9'|'_'
                                            => {}
                                            _ => {
                                                offset = off;
                                                break;
                                            }
                                        }
                                    }
                                    None => break,
                                }
                                self.iter.next();
                            }
                            let value = &self.data[off..offset];
                            let tok = match value {
                                "css" => TokenType::Css,
                                "html" => TokenType::Html,
                                "import" => TokenType::Import,
                                "from" => TokenType::From,
                                "if" => TokenType::If,
                                "for" => TokenType::For,
                                "in" => TokenType::In,
                                "of" => TokenType::Of,
                                "as" => TokenType::As,
                                "else" => TokenType::Else,
                                _ => TokenType::Ident,
                            };
                            return Some((tok, value, pos));
                        }
                        _ => {
                            return None; // Unexpected character
                        }
                    }
                }
                None => {
                    let pos = SourcePosition {
                        line: self.iter.line,
                        column: self.iter.column,
                        };
                    match self.indents.pop() {
                        Some(level) if level > 0 => {
                            return Some((TokenType::Dedent, "", pos));
                        }
                        _ => {
                            return Some((TokenType::Eof, "", pos));
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>Fix recently introduced bug in tokenizer<commit_after>use std::str::{Chars};
use std::iter::Peekable;

use parser_combinators::primitives::{SourcePosition};
use unicode_segmentation::{UnicodeSegmentation, GraphemeIndices};

use super::token::{Token, TokenType};

#[derive(Clone)]
struct CodeIter<'a> {
    iter: GraphemeIndices<'a>,
    buf: Option<Peekable<Chars<'a>>>,
    grapheme: Option<&'a str>,
    offset: usize,
    line: i32,
    column: i32,
}

impl <'a> Iterator for CodeIter<'a> {
    type Item = (char, usize, i32, i32);

    fn next(&mut self) -> Option<(char, usize, i32, i32)> {
        if self.buf.is_none() {
            if self.peek().is_none() {
                return None;
            }
        }
        if let Some(ref mut buf) = self.buf {
            match buf.next() {
                Some(ch) => {
                    return Some((ch, self.offset, self.line, self.column));
                }
                None => {}
            }
        }
        self.buf = None;
        return self.next();
    }
}

impl <'a> CodeIter<'a> {
    fn peek(&mut self) -> Option<(char, usize, i32, i32)> {
        if let Some(ref mut buf) = self.buf {
            if let Some(ch) = buf.peek() {
                return Some((*ch, self.offset, self.line, self.column));
            }
        }
        if let Some(gr) = self.grapheme {
            if gr == "\n" {
                self.line += 1;
                self.column = 1;
            } else {
                self.column += 1;
            }
            self.offset += gr.as_bytes().len();
            self.buf = None;
            self.grapheme = None;
        }
        match self.iter.next() {
            Some((_, grapheme)) => {
                self.grapheme = Some(grapheme);
                self.buf = Some(grapheme.chars().peekable());
                self.peek()
            }
            None => None,
        }
    }
}

#[derive(Clone)]
pub struct Tokenizer<'a> {
    data: &'a str,
    iter: CodeIter<'a>,
    braces: Vec<char>,
    indents: Vec<usize>,
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Token<'a>;
    fn next(&mut self) -> Option<Token<'a>> {
        let tok = self._next();
        println!("Next token {:?}", tok);
        return tok;
    }
}

impl<'a> Tokenizer<'a> {
    pub fn new(val: &'a str) -> Tokenizer<'a> {
        return Tokenizer {
            data: val,
            iter: CodeIter {
                iter: UnicodeSegmentation::grapheme_indices(val, true),
                buf: None,
                grapheme: None,
                offset: 0,
                line: 1,
                column: 1,
                },
            braces: vec!(),
            indents: vec!(0),
        };
    }
    fn _next(&mut self) -> Option<Token<'a>> {
        'outer: loop {
            match self.iter.peek() {
                Some((ch, _, _, 1)) if ch != ' ' && self.indents.len() > 1 => {
                    self.indents.pop().unwrap();
                    let pos = SourcePosition {
                        line: self.iter.line,
                        column: self.iter.column,
                        };
                    return Some((TokenType::Dedent, "", pos));
                }
                _ => {}
            }
            match self.iter.next() {
                Some((ch, off, line, column)) => {
                    let pos = SourcePosition {
                        line: line,
                        column: column,
                        };
                    match ch {
                        '\n' => {
                            if column == 1 {
                                continue;  // skip empty line
                            }
                            return Some((TokenType::Newline, "\n", pos));
                        }
                        '('|'{'|'[' => {
                            let typ = match ch {
                                '(' => TokenType::OpenParen,
                                '{' => TokenType::OpenBrace,
                                '[' => TokenType::OpenBracket,
                                _ => unreachable!(),
                            };
                            self.braces.push(ch);
                            return Some((typ, &self.data[off..off+1], pos));
                        }
                        ')'|'}'|']' => {
                            let (typ, val) = match ch {
                                ')' => (TokenType::CloseParen, '('),
                                '}' => (TokenType::CloseBrace, '{'),
                                ']' => (TokenType::CloseBracket, '['),
                                _ => unreachable!(),
                            };
                            let br = self.braces.pop();
                            if Some(val) == br {
                                return Some((typ, &self.data[off..off+1], pos));
                            } else {
                                // TODO(tailhook) how to communicate error?
                                return None;
                            }
                        }
                        ':'|'.'|'='|'-'|',' => {
                            let typ = match ch {
                                ':' => TokenType::Colon,
                                '.' => TokenType::Dot,
                                '=' => TokenType::Equals,
                                '-' => TokenType::Dash,
                                ',' => TokenType::Comma,
                                _ => unreachable!(),
                            };
                            return Some((typ, &self.data[off..off+1], pos));
                        }
                        '#' => {
                            loop {
                                match self.iter.next() {
                                    Some(('\n', _, _, _)) | None => break,
                                    Some(_) => {}
                                }
                            }
                            continue;
                        }
                        '"'|'\'' => {
                            let dlm = ch;
                            loop {
                                match self.iter.next() {
                                    Some((ch, _, _, _)) if ch == dlm => {
                                        break;
                                    }
                                    Some(('\\', _, _, _)) => {
                                        // any char allowed after slash
                                        self.iter.next();
                                    }
                                    Some(_) => {}
                                    None => {
                                        // TODO(tailhook) return error
                                        break;
                                    }
                                }
                            }
                            let value = &self.data[off..self.iter.offset+1];
                            return Some((TokenType::String, value, pos));
                        }
                        ' ' if column == 1 => {
                            let mut offset;
                            let mut indent;
                            loop {
                                match self.iter.peek() {
                                    Some(('\n', _, _, _)) => {
                                        self.iter.next();  // skip empty line
                                        continue 'outer;
                                    }
                                    Some((' ', _, _, _)) => {
                                        self.iter.next();
                                        continue;
                                    }
                                    Some(('#', _, _, _)) => {
                                        continue 'outer;
                                    }
                                    Some((_, off, _, col)) => {
                                        offset = off;
                                        indent = (col - 1) as usize;
                                        break;
                                    }
                                    None => {
                                        continue 'outer;  // WS at EOF
                                    }
                                }
                            }
                            let chunk = &self.data[off..offset];
                            let mut typ;
                            let curindent = *self.indents.last().unwrap();
                            if indent == curindent {
                                continue;
                            } else if indent > curindent {
                                self.indents.push(indent);
                                typ = TokenType::Indent;
                            } else {
                                loop {
                                    let nindent = self.indents.pop().unwrap();
                                    if nindent == indent {
                                        self.indents.push(indent);
                                        break;
                                    } else if nindent < indent {
                                        // TODO(tailhook) how to report err?
                                        return None;
                                    }
                                }
                                typ = TokenType::Dedent;
                            }
                            return Some((typ, chunk, pos));
                        }
                        ' '|'\t' => {  // Skip whitespace
                            continue;
                        }
                        'a'...'z'|'A'...'Z'|'_' => {
                            let mut offset = self.data.len();
                            loop {
                                match self.iter.peek() {
                                    Some((x, off, _, _)) => {
                                        match x {
                                            'a'...'z'|'A'...'Z'|'0'...'9'|'_'
                                            => {}
                                            _ => {
                                                offset = off;
                                                break;
                                            }
                                        }
                                    }
                                    None => break,
                                }
                                self.iter.next();
                            }
                            let value = &self.data[off..offset];
                            let tok = match value {
                                "css" => TokenType::Css,
                                "html" => TokenType::Html,
                                "import" => TokenType::Import,
                                "from" => TokenType::From,
                                "if" => TokenType::If,
                                "for" => TokenType::For,
                                "in" => TokenType::In,
                                "of" => TokenType::Of,
                                "as" => TokenType::As,
                                "else" => TokenType::Else,
                                _ => TokenType::Ident,
                            };
                            return Some((tok, value, pos));
                        }
                        _ => {
                            return None; // Unexpected character
                        }
                    }
                }
                None => {
                    let pos = SourcePosition {
                        line: self.iter.line,
                        column: self.iter.column,
                        };
                    match self.indents.pop() {
                        Some(level) if level > 0 => {
                            return Some((TokenType::Dedent, "", pos));
                        }
                        _ => {
                            return Some((TokenType::Eof, "", pos));
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.static_root_path.unwrap_or(page.root_path);
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
            \
        </button>\

\

\
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" class=\"help-button\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\

\
    {after_content}\

    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = page.description,
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<commit_msg>rustdoc: Show nag box on IE10<commit_after>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.static_root_path.unwrap_or(page.root_path);
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
            \
        </button>\

\

\
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" class=\"help-button\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\

\
    {after_content}\

    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = page.description,
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<|endoftext|>