<commit_before>#![allow(dead_code)]

use {Signature};
use std::{fmt, any};
use std::sync::Arc;
use std::rc::Rc;

use super::{Iter, IterAppend, ArgType};

/// Types that can represent a D-Bus message argument implement this trait.
///
/// Types should also implement either Append or Get to be useful.
pub trait Arg {
    /// The corresponding D-Bus argument type code.
    fn arg_type() -> ArgType;
    /// The corresponding D-Bus type signature for this type.
    fn signature() -> Signature<'static>;
}

/// Types that can be appended to a message as arguments implement this trait.
pub trait Append: Sized {
    /// Performs the append operation.
    fn append(self, &mut IterAppend);
}

/// Types that can be retrieved from a message as arguments implement this trait.
pub trait Get<'a>: Sized {
    /// Performs the get operation.
    fn get(i: &mut Iter<'a>) -> Option<Self>;
}

/// Object safe version of Arg + Append + Get.
///
/// This trait is somewhat under development, which means that not all types are supported
/// and that the API might change. Only use in case Arg is not dynamic enough for your needs.
pub trait RefArg: fmt::Debug {
    /// The corresponding D-Bus argument type code.
    fn arg_type(&self) -> ArgType;
    /// The corresponding D-Bus type signature for this type.
    fn signature(&self) -> Signature<'static>;
    /// Performs the append operation.
    fn append(&self, &mut IterAppend);
    /// Transforms this argument to Any (which can be downcasted to read the current value).
    fn as_any(&self) -> &any::Any where Self: 'static;
    /// Transforms this argument to Any (which can be downcasted to read the current value).
    fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static;
    /// Try to read the argument as an i64.
    #[inline]
    fn as_i64(&self) -> Option<i64> { None }
    /// Try to read the argument as a str.
    #[inline]
    fn as_str(&self) -> Option<&str> { None }
    /// Try to read the argument as an iterator.
    #[inline]
    fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { None }
}

/// Cast a RefArg as a specific type (shortcut for any + downcast)
#[inline]
pub fn cast<'a, T: 'static>(a: &'a (RefArg + 'static)) -> Option<&'a T> { a.as_any().downcast_ref() }

/// Cast a RefArg as a specific type (shortcut for any_mut + downcast_mut)
#[inline]
pub fn cast_mut<'a, T: 'static>(a: &'a mut (RefArg + 'static)) -> Option<&'a mut T> { a.as_any_mut().downcast_mut() }

/// If a type implements this trait, it means the size and alignment is the same
/// as in D-Bus. This means that you can quickly append and get slices of this type.
///
/// Note: Booleans do not implement this trait because D-Bus booleans are 4 bytes and Rust booleans are 1 byte.
pub unsafe trait FixedArray: Arg + 'static + Clone + Copy {}

/// Types that can be used as keys in a dict type implement this trait.
pub trait DictKey: Arg {}

/// Simple lift over reference to value - this makes some iterators more ergonomic to use
impl<'a, T: Arg> Arg for &'a T {
    fn arg_type() -> ArgType { T::arg_type() }
    fn signature() -> Signature<'static> { T::signature() }
}
impl<'a, T: Append + Clone> Append for &'a T {
    fn append(self, i: &mut IterAppend) { self.clone().append(i) }
}
impl<'a, T: DictKey> DictKey for &'a T {}

impl<'a, T: RefArg + ?Sized> RefArg for &'a T {
    #[inline]
    fn arg_type(&self) -> ArgType { (&**self).arg_type() }
    #[inline]
    fn signature(&self) -> Signature<'static> { (&**self).signature() }
    #[inline]
    fn append(&self, i: &mut IterAppend) { (&**self).append(i) }
    #[inline]
    fn as_any(&self) -> &any::Any where T: 'static { (&**self).as_any() }
    #[inline]
    fn as_any_mut(&mut self) -> &mut any::Any where T: 'static { unreachable!() }
    #[inline]
    fn as_i64(&self) -> Option<i64> { (&**self).as_i64() }
    #[inline]
    fn as_str(&self) -> Option<&str> { (&**self).as_str() }
    #[inline]
    fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> { (&**self).as_iter() }
}

macro_rules! deref_impl {
    ($t: ident, $ss: ident, $make_mut: expr) => {

impl<T: RefArg + ?Sized> RefArg for $t<T> {
    #[inline]
    fn arg_type(&self) -> ArgType { (&**self).arg_type() }
    #[inline]
    fn signature(&self) -> Signature<'static> { (&**self).signature() }
    #[inline]
    fn append(&self, i: &mut IterAppend) { (&**self).append(i) }
    #[inline]
    fn as_any(&self) -> &any::Any where T: 'static { (&**self).as_any() }
    #[inline]
    fn as_any_mut<'a>(&'a mut self) -> &'a mut any::Any where T: 'static { $make_mut(self).as_any_mut() }
    #[inline]
    fn as_i64(&self) -> Option<i64> { (&**self).as_i64() }
    #[inline]
    fn as_str(&self) -> Option<&str> { (&**self).as_str() }
    #[inline]
    fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { (&**self).as_iter() }
}
impl<T: DictKey> DictKey for $t<T> {}

impl<T: Arg> Arg for $t<T> {
    fn arg_type() -> ArgType { T::arg_type() }
    fn signature() -> Signature<'static> { T::signature() }
}
impl<'a, T: Get<'a>> Get<'a> for $t<T> {
    fn get(i: &mut Iter<'a>) -> Option<Self> { T::get(i).map(|v| $t::new(v)) }
}

    }
}

impl<T: Append> Append for Box<T> {
    fn append(self, i: &mut IterAppend) { let q: T = *self; q.append(i) }
}

deref_impl!(Box, ss, |q: &'a mut Box<T>| -> &'a mut T { &mut **q });
deref_impl!(Rc, ss, |q| Rc::get_mut(q).unwrap());
deref_impl!(Arc, ss, |q| Arc::get_mut(q).unwrap());

#[cfg(test)]
mod test {
    extern crate tempdir;

    use {Connection, ConnectionItem, Message, BusType, Path, Signature};
    use arg::{Array, Variant, Dict, Iter, ArgType, TypeMismatchError, RefArg, cast};

    use std::collections::HashMap;

    #[test]
    fn refarg() {
        let c = Connection::get_private(BusType::Session).unwrap();
        c.register_object_path("/mooh").unwrap();
        let m = Message::new_method_call(&c.unique_name(), "/mooh", "com.example.hello", "Hello").unwrap();

        let mut vv: Vec<Variant<Box<RefArg>>> = vec!();
        vv.push(Variant(Box::new(5i32)));
        vv.push(Variant(Box::new(String::from("Hello world"))));
        let m = m.append_ref(&vv);

        let (f1, f2) = (false, 7u64);
        let mut v: Vec<&RefArg> = vec!();
        v.push(&f1);
        v.push(&f2);
        let m = m.append_ref(&v);
        let vi32 = vec![7i32, 9i32];
        let vstr: Vec<String> = ["This", "is", "dbus", "rs"].iter().map(|&s| s.into()).collect();
        let m = m.append_ref(&[&vi32 as &RefArg, &vstr as &RefArg]);
        let mut map = HashMap::new();
        map.insert(true, String::from("Yes"));
        map.insert(false, String::from("No"));
        let m = m.append_ref(&[&map]);

        c.send(m).unwrap();

        for n in c.iter(1000) {
            if let ConnectionItem::MethodCall(m) = n {
                let rv: Vec<Box<RefArg + 'static>> = m.iter_init().collect();
                println!("Receiving {:?}", rv);
                let rv0: &Variant<Box<RefArg>> = cast(&rv[0]).unwrap();
                let rv00: &i32 = cast(&rv0.0).unwrap();
                assert_eq!(rv00, &5i32);
                assert_eq!(Some(&false), rv[2].as_any().downcast_ref::<bool>());
                assert_eq!(Some(&vi32), rv[4].as_any().downcast_ref::<Vec<i32>>());
                assert_eq!(Some(&vstr), rv[5].as_any().downcast_ref::<Vec<String>>());
                let mmap: &HashMap<bool, Variant<Box<RefArg>>> = cast(&rv[6]).unwrap();
                assert_eq!(mmap[&true].as_str(), Some("Yes"));
                let mut iter = rv[6].as_iter().unwrap();
                assert!(iter.next().unwrap().as_i64().is_some());
                assert!(iter.next().unwrap().as_str().is_some());
                assert!(iter.next().unwrap().as_str().is_none());
                assert!(iter.next().unwrap().as_i64().is_none());
                assert!(iter.next().is_none());
                break;
            }
        }
    }

    #[test]
    fn message_types() {
        let c = Connection::get_private(BusType::Session).unwrap();
        c.register_object_path("/hello").unwrap();
        let m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap();
        let m = m.append1(2000u16);
        let m = m.append1(Array::new(&vec![129u8, 5, 254]));
        let m = m.append2(Variant(&["Hello", "world"][..]), &[32768u16, 16u16, 12u16][..]);
        let m = m.append3(-1i32, &*format!("Hello world"), -3.14f64);
        let m = m.append1((256i16, Variant(18_446_744_073_709_551_615u64)));
        let m = m.append2(Path::new("/a/valid/path").unwrap(), Signature::new("a{sv}").unwrap());
        let mut z = HashMap::new();
        z.insert(123543u32, true);
        z.insert(0u32, false);
        let m = m.append1(Dict::new(&z));
        let sending = format!("{:?}", m.iter_init());
        println!("Sending {}", sending);
        c.send(m).unwrap();

        for n in c.iter(1000) {
            match n {
                ConnectionItem::MethodCall(m) => {
                    use super::Arg;
                    let receiving = format!("{:?}", m.iter_init());
                    println!("Receiving {}", receiving);
                    assert_eq!(sending, receiving);

                    assert_eq!(2000u16, m.get1().unwrap());
                    assert_eq!(m.get2(), (Some(2000u16), Some(&[129u8, 5, 254][..])));
                    assert_eq!(m.read2::<u16, bool>().unwrap_err(),
                        TypeMismatchError { position: 1, found: ArgType::Array, expected: ArgType::Boolean });

                    let mut g = m.iter_init();
                    let e = g.read::<u32>().unwrap_err();
                    assert_eq!(e.pos(), 0);
                    assert_eq!(e.expected_arg_type(), ArgType::UInt32);
                    assert_eq!(e.found_arg_type(), ArgType::UInt16);

                    assert!(g.next() && g.next());
                    let v: Variant<Iter> = g.get().unwrap();
                    let mut viter = v.0;
                    assert_eq!(viter.arg_type(), Array::<&str,()>::arg_type());
                    let a: Array<&str, _> = viter.get().unwrap();
                    assert_eq!(a.collect::<Vec<&str>>(), vec!["Hello", "world"]);

                    assert!(g.next());
                    assert_eq!(g.get::<u16>(), None); // It's an array, not a single u16
                    assert!(g.next() && g.next() && g.next() && g.next());

                    assert_eq!(g.get(), Some((256i16, Variant(18_446_744_073_709_551_615u64))));
                    assert!(g.next());
                    assert_eq!(g.get(), Some(Path::new("/a/valid/path").unwrap()));
                    assert!(g.next());
                    assert_eq!(g.get(), Some(Signature::new("a{sv}").unwrap()));
                    assert!(g.next());
                    let d: Dict<u32, bool, _> = g.get().unwrap();
                    let z2: HashMap<_, _> = d.collect();
                    assert_eq!(z, z2);
                    break;
                }
                _ => println!("Got {:?}", n),
            }
        }
    }
}
<commit_msg>Improve make_mut solution<commit_after>#![allow(dead_code)]

use {Signature};
use std::{fmt, any};
use std::sync::Arc;
use std::rc::Rc;

use super::{Iter, IterAppend, ArgType};

/// Types that can represent a D-Bus message argument implement this trait.
///
/// Types should also implement either Append or Get to be useful.
pub trait Arg {
    /// The corresponding D-Bus argument type code.
    fn arg_type() -> ArgType;
    /// The corresponding D-Bus type signature for this type.
    fn signature() -> Signature<'static>;
}

/// Types that can be appended to a message as arguments implement this trait.
pub trait Append: Sized {
    /// Performs the append operation.
    fn append(self, &mut IterAppend);
}

/// Types that can be retrieved from a message as arguments implement this trait.
pub trait Get<'a>: Sized {
    /// Performs the get operation.
    fn get(i: &mut Iter<'a>) -> Option<Self>;
}

/// Object safe version of Arg + Append + Get.
///
/// This trait is somewhat under development, which means that not all types are supported
/// and that the API might change. Only use in case Arg is not dynamic enough for your needs.
pub trait RefArg: fmt::Debug {
    /// The corresponding D-Bus argument type code.
    fn arg_type(&self) -> ArgType;
    /// The corresponding D-Bus type signature for this type.
    fn signature(&self) -> Signature<'static>;
    /// Performs the append operation.
    fn append(&self, &mut IterAppend);
    /// Transforms this argument to Any (which can be downcasted to read the current value).
    fn as_any(&self) -> &any::Any where Self: 'static;
    /// Transforms this argument to Any (which can be downcasted to read the current value).
    ///
    /// # Panic
    /// Will panic if the interior cannot be made mutable, e g, if encapsulated
    /// inside a Rc with a reference count > 1.
    fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static;
    /// Try to read the argument as an i64.
    #[inline]
    fn as_i64(&self) -> Option<i64> { None }
    /// Try to read the argument as a str.
    #[inline]
    fn as_str(&self) -> Option<&str> { None }
    /// Try to read the argument as an iterator.
    #[inline]
    fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { None }
}

/// Cast a RefArg as a specific type (shortcut for any + downcast)
#[inline]
pub fn cast<'a, T: 'static>(a: &'a (RefArg + 'static)) -> Option<&'a T> { a.as_any().downcast_ref() }

/// Cast a RefArg as a specific type (shortcut for any_mut + downcast_mut)
///
/// # Panic
/// Will panic if the interior cannot be made mutable, e g, if encapsulated
/// inside a Rc with a reference count > 1.
#[inline]
pub fn cast_mut<'a, T: 'static>(a: &'a mut (RefArg + 'static)) -> Option<&'a mut T> { a.as_any_mut().downcast_mut() }

/// If a type implements this trait, it means the size and alignment is the same
/// as in D-Bus. This means that you can quickly append and get slices of this type.
///
/// Note: Booleans do not implement this trait because D-Bus booleans are 4 bytes and Rust booleans are 1 byte.
pub unsafe trait FixedArray: Arg + 'static + Clone + Copy {}

/// Types that can be used as keys in a dict type implement this trait.
pub trait DictKey: Arg {}

/// Simple lift over reference to value - this makes some iterators more ergonomic to use
impl<'a, T: Arg> Arg for &'a T {
    fn arg_type() -> ArgType { T::arg_type() }
    fn signature() -> Signature<'static> { T::signature() }
}
impl<'a, T: Append + Clone> Append for &'a T {
    fn append(self, i: &mut IterAppend) { self.clone().append(i) }
}
impl<'a, T: DictKey> DictKey for &'a T {}

impl<'a, T: RefArg + ?Sized> RefArg for &'a T {
    #[inline]
    fn arg_type(&self) -> ArgType { (&**self).arg_type() }
    #[inline]
    fn signature(&self) -> Signature<'static> { (&**self).signature() }
    #[inline]
    fn append(&self, i: &mut IterAppend) { (&**self).append(i) }
    #[inline]
    fn as_any(&self) -> &any::Any where T: 'static { (&**self).as_any() }
    #[inline]
    fn as_any_mut(&mut self) -> &mut any::Any where T: 'static { unreachable!() }
    #[inline]
    fn as_i64(&self) -> Option<i64> { (&**self).as_i64() }
    #[inline]
    fn as_str(&self) -> Option<&str> { (&**self).as_str() }
    #[inline]
    fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> { (&**self).as_iter() }
}

macro_rules! deref_impl {
    ($t: ident, $ss: ident, $make_mut: expr) => {

impl<T: RefArg + ?Sized> RefArg for $t<T> {
    #[inline]
    fn arg_type(&self) -> ArgType { (&**self).arg_type() }
    #[inline]
    fn signature(&self) -> Signature<'static> { (&**self).signature() }
    #[inline]
    fn append(&self, i: &mut IterAppend) { (&**self).append(i) }
    #[inline]
    fn as_any(&self) -> &any::Any where T: 'static { (&**self).as_any() }
    #[inline]
    fn as_any_mut<'a>(&'a mut $ss) -> &'a mut any::Any where T: 'static { $make_mut.as_any_mut() }
    #[inline]
    fn as_i64(&self) -> Option<i64> { (&**self).as_i64() }
    #[inline]
    fn as_str(&self) -> Option<&str> { (&**self).as_str() }
    #[inline]
    fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { (&**self).as_iter() }
}
impl<T: DictKey> DictKey for $t<T> {}

impl<T: Arg> Arg for $t<T> {
    fn arg_type() -> ArgType { T::arg_type() }
    fn signature() -> Signature<'static> { T::signature() }
}
impl<'a, T: Get<'a>> Get<'a> for $t<T> {
    fn get(i: &mut Iter<'a>) -> Option<Self> { T::get(i).map(|v| $t::new(v)) }
}

    }
}

impl<T: Append> Append for Box<T> {
    fn append(self, i: &mut IterAppend) { let q: T = *self; q.append(i) }
}

deref_impl!(Box, self, &mut **self );
deref_impl!(Rc, self, Rc::get_mut(self).unwrap());
deref_impl!(Arc, self, Arc::get_mut(self).unwrap());

#[cfg(test)]
mod test {
    extern crate tempdir;

    use {Connection, ConnectionItem, Message, BusType, Path, Signature};
    use arg::{Array, Variant, Dict, Iter, ArgType, TypeMismatchError, RefArg, cast};

    use std::collections::HashMap;

    #[test]
    fn refarg() {
        let c = Connection::get_private(BusType::Session).unwrap();
        c.register_object_path("/mooh").unwrap();
        let m = Message::new_method_call(&c.unique_name(), "/mooh", "com.example.hello", "Hello").unwrap();

        let mut vv: Vec<Variant<Box<RefArg>>> = vec!();
        vv.push(Variant(Box::new(5i32)));
        vv.push(Variant(Box::new(String::from("Hello world"))));
        let m = m.append_ref(&vv);

        let (f1, f2) = (false, 7u64);
        let mut v: Vec<&RefArg> = vec!();
        v.push(&f1);
        v.push(&f2);
        let m = m.append_ref(&v);
        let vi32 = vec![7i32, 9i32];
        let vstr: Vec<String> = ["This", "is", "dbus", "rs"].iter().map(|&s| s.into()).collect();
        let m = m.append_ref(&[&vi32 as &RefArg, &vstr as &RefArg]);
        let mut map = HashMap::new();
        map.insert(true, String::from("Yes"));
        map.insert(false, String::from("No"));
        let m = m.append_ref(&[&map]);

        c.send(m).unwrap();

        for n in c.iter(1000) {
            if let ConnectionItem::MethodCall(m) = n {
                let rv: Vec<Box<RefArg + 'static>> = m.iter_init().collect();
                println!("Receiving {:?}", rv);
                let rv0: &Variant<Box<RefArg>> = cast(&rv[0]).unwrap();
                let rv00: &i32 = cast(&rv0.0).unwrap();
                assert_eq!(rv00, &5i32);
                assert_eq!(Some(&false), rv[2].as_any().downcast_ref::<bool>());
                assert_eq!(Some(&vi32), rv[4].as_any().downcast_ref::<Vec<i32>>());
                assert_eq!(Some(&vstr), rv[5].as_any().downcast_ref::<Vec<String>>());
                let mmap: &HashMap<bool, Variant<Box<RefArg>>> = cast(&rv[6]).unwrap();
                assert_eq!(mmap[&true].as_str(), Some("Yes"));
                let mut iter = rv[6].as_iter().unwrap();
                assert!(iter.next().unwrap().as_i64().is_some());
                assert!(iter.next().unwrap().as_str().is_some());
                assert!(iter.next().unwrap().as_str().is_none());
                assert!(iter.next().unwrap().as_i64().is_none());
                assert!(iter.next().is_none());
                break;
            }
        }
    }

    #[test]
    fn message_types() {
        let c = Connection::get_private(BusType::Session).unwrap();
        c.register_object_path("/hello").unwrap();
        let m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap();
        let m = m.append1(2000u16);
        let m = m.append1(Array::new(&vec![129u8, 5, 254]));
        let m = m.append2(Variant(&["Hello", "world"][..]), &[32768u16, 16u16, 12u16][..]);
        let m = m.append3(-1i32, &*format!("Hello world"), -3.14f64);
        let m = m.append1((256i16, Variant(18_446_744_073_709_551_615u64)));
        let m = m.append2(Path::new("/a/valid/path").unwrap(), Signature::new("a{sv}").unwrap());
        let mut z = HashMap::new();
        z.insert(123543u32, true);
        z.insert(0u32, false);
        let m = m.append1(Dict::new(&z));
        let sending = format!("{:?}", m.iter_init());
        println!("Sending {}", sending);
        c.send(m).unwrap();

        for n in c.iter(1000) {
            match n {
                ConnectionItem::MethodCall(m) => {
                    use super::Arg;
                    let receiving = format!("{:?}", m.iter_init());
                    println!("Receiving {}", receiving);
                    assert_eq!(sending, receiving);

                    assert_eq!(2000u16, m.get1().unwrap());
                    assert_eq!(m.get2(), (Some(2000u16), Some(&[129u8, 5, 254][..])));
                    assert_eq!(m.read2::<u16, bool>().unwrap_err(),
                        TypeMismatchError { position: 1, found: ArgType::Array, expected: ArgType::Boolean });

                    let mut g = m.iter_init();
                    let e = g.read::<u32>().unwrap_err();
                    assert_eq!(e.pos(), 0);
                    assert_eq!(e.expected_arg_type(), ArgType::UInt32);
                    assert_eq!(e.found_arg_type(), ArgType::UInt16);

                    assert!(g.next() && g.next());
                    let v: Variant<Iter> = g.get().unwrap();
                    let mut viter = v.0;
                    assert_eq!(viter.arg_type(), Array::<&str,()>::arg_type());
                    let a: Array<&str, _> = viter.get().unwrap();
                    assert_eq!(a.collect::<Vec<&str>>(), vec!["Hello", "world"]);

                    assert!(g.next());
                    assert_eq!(g.get::<u16>(), None); // It's an array, not a single u16
                    assert!(g.next() && g.next() && g.next() && g.next());

                    assert_eq!(g.get(), Some((256i16, Variant(18_446_744_073_709_551_615u64))));
                    assert!(g.next());
                    assert_eq!(g.get(), Some(Path::new("/a/valid/path").unwrap()));
                    assert!(g.next());
                    assert_eq!(g.get(), Some(Signature::new("a{sv}").unwrap()));
                    assert!(g.next());
                    let d: Dict<u32, bool, _> = g.get().unwrap();
                    let z2: HashMap<_, _> = d.collect();
                    assert_eq!(z, z2);
                    break;
                }
                _ => println!("Got {:?}", n),
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Support for JPG image decoding.
use snafu::{OptionExt, ResultExt};

use super::{CustomMessageSnafu, CustomSnafu, MissingAttributeSnafu};
use crate::adapters::{DecodeResult, PixelDataObject, PixelRWAdapter};
use jpeg_decoder::Decoder;
use std::io::Cursor;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct JPEGAdapter;

impl PixelRWAdapter for JPEGAdapter {
    /// Decode DICOM image data with jpeg encoding.

    fn decode(&self, src: &dyn PixelDataObject, dst: &mut Vec<u8>) -> DecodeResult<()> {
        let cols = src
            .cols()
            .context(MissingAttributeSnafu { name: "Columns" })?;
        let rows = src.rows().context(MissingAttributeSnafu { name: "Rows" })?;
        let samples_per_pixel = src.samples_per_pixel().context(MissingAttributeSnafu {
            name: "SamplesPerPixel",
        })?;
        let bits_allocated = src.bits_allocated().context(MissingAttributeSnafu {
            name: "BitsAllocated",
        })?;

        if bits_allocated != 8 && bits_allocated != 16 {
            return CustomMessageSnafu {
                message: "BitsAllocated other than 8 or 16 is not supported",
            }
            .fail();
        }

        let nr_frames = src.number_of_frames().unwrap_or(1) as usize;
        let bytes_per_sample = bits_allocated / 8;

        // `stride` it the total number of bytes for each sample plane
        let stride: usize = bytes_per_sample as usize * cols as usize * rows as usize;
        dst.resize((samples_per_pixel as usize * stride) * nr_frames, 0);

        // Embedded jpegs can span multiple fragments
        // Hence we collect all fragments into single vector
        // and then just iterate a cursor for each frame
        let fragments: Vec<u8> = src
            .raw_pixel_data()
            .context(CustomMessageSnafu {
                message: "Expected to have raw pixel data available",
            })?
            .fragments
            .into_iter()
            .flatten()
            .collect();

        let fragments_len = fragments.len() as u64;
        let mut cursor = Cursor::new(fragments);

        let mut dst_offset = 0;

        loop {
            // dicom fields always have to have an even length and fill this space with padding
            // if uneven we have to move one position further to consume this padding
            if cursor.position() % 2 > 0 {
                cursor.set_position(cursor.position() + 1);
            }

            if cursor.position() >= fragments_len {
                break;
            }
            let mut decoder = Decoder::new(&mut cursor);
            let decoded = decoder
                .decode()
                .map_err(|e| Box::new(e) as Box<_>)
                .context(CustomSnafu)?;

            let decoded_len = decoded.len();
            dst[dst_offset..(dst_offset + decoded_len)].copy_from_slice(&decoded);
            dst_offset += decoded_len
        }

        Ok(())
    }
}
<commit_msg>Fix import ordering<commit_after>//! Support for JPG image decoding.

use super::{CustomMessageSnafu, CustomSnafu, MissingAttributeSnafu};
use crate::adapters::{DecodeResult, PixelDataObject, PixelRWAdapter};
use jpeg_decoder::Decoder;
use snafu::{OptionExt, ResultExt};
use std::io::Cursor;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct JPEGAdapter;

impl PixelRWAdapter for JPEGAdapter {
    /// Decode DICOM image data with jpeg encoding.

    fn decode(&self, src: &dyn PixelDataObject, dst: &mut Vec<u8>) -> DecodeResult<()> {
        let cols = src
            .cols()
            .context(MissingAttributeSnafu { name: "Columns" })?;
        let rows = src.rows().context(MissingAttributeSnafu { name: "Rows" })?;
        let samples_per_pixel = src.samples_per_pixel().context(MissingAttributeSnafu {
            name: "SamplesPerPixel",
        })?;
        let bits_allocated = src.bits_allocated().context(MissingAttributeSnafu {
            name: "BitsAllocated",
        })?;

        if bits_allocated != 8 && bits_allocated != 16 {
            return CustomMessageSnafu {
                message: "BitsAllocated other than 8 or 16 is not supported",
            }
            .fail();
        }

        let nr_frames = src.number_of_frames().unwrap_or(1) as usize;
        let bytes_per_sample = bits_allocated / 8;

        // `stride` it the total number of bytes for each sample plane
        let stride: usize = bytes_per_sample as usize * cols as usize * rows as usize;
        dst.resize((samples_per_pixel as usize * stride) * nr_frames, 0);

        // Embedded jpegs can span multiple fragments
        // Hence we collect all fragments into single vector
        // and then just iterate a cursor for each frame
        let fragments: Vec<u8> = src
            .raw_pixel_data()
            .context(CustomMessageSnafu {
                message: "Expected to have raw pixel data available",
            })?
            .fragments
            .into_iter()
            .flatten()
            .collect();

        let fragments_len = fragments.len() as u64;
        let mut cursor = Cursor::new(fragments);

        let mut dst_offset = 0;

        loop {
            // dicom fields always have to have an even length and fill this space with padding
            // if uneven we have to move one position further to consume this padding
            if cursor.position() % 2 > 0 {
                cursor.set_position(cursor.position() + 1);
            }

            if cursor.position() >= fragments_len {
                break;
            }
            let mut decoder = Decoder::new(&mut cursor);
            let decoded = decoder
                .decode()
                .map_err(|e| Box::new(e) as Box<_>)
                .context(CustomSnafu)?;

            let decoded_len = decoded.len();
            dst[dst_offset..(dst_offset + decoded_len)].copy_from_slice(&decoded);
            dst_offset += decoded_len
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use ndarray::Array2;
use rand::{seq::SliceRandom, thread_rng, Rng};
use std::f64;

pub fn argmaxima<I: IntoIterator<Item = f64>>(vals: I) -> (Vec<usize>, f64) {
    let mut max = f64::MIN;
    let mut ixs = vec![];

    for (i, v) in vals.into_iter().enumerate() {
        if (v - max).abs() < 1e-7 {
            ixs.push(i);
        } else if v > max {
            max = v;
            ixs.clear();
            ixs.push(i);
        }
    }

    (ixs, max)
}

pub fn argmax_first<I: IntoIterator<Item = f64>>(vals: I) -> (usize, f64) {
    vals.into_iter().enumerate().fold(
        (0, f64::MIN),
        |(i, x), (j, y)| {
            if y - x > 1e-7 {
                (j, y)
            } else {
                (i, x)
            }
        },
    )
}

pub fn argmax_last<I: IntoIterator<Item = f64>>(vals: I) -> (usize, f64) {
    vals.into_iter().enumerate().fold(
        (0, f64::MIN),
        |(i, x), (j, y)| {
            if y - x > -1e-7 {
                (j, y)
            } else {
                (i, x)
            }
        },
    )
}

pub fn argmax_choose<I: IntoIterator<Item = f64>>(vals: I) -> (usize, f64) {
    let (maxima, value) = argmaxima(vals);

    let maximum = if maxima.len() == 1 {
        maxima[0]
    } else {
        *maxima
            .choose(&mut thread_rng())
            .expect("No valid maxima to choose from in `argmax_choose`.")
    };

    (maximum, value)
}

pub fn argmax_choose_rng<R, I>(rng: &mut R, vals: I) -> (usize, f64)
where
    R: Rng + ?Sized,
    I: IntoIterator<Item = f64>,
{
    let (maxima, value) = argmaxima(vals);

    let maximum = if maxima.len() == 1 {
        maxima[0]
    } else {
        *maxima
            .choose(rng)
            .expect("No valid maxima to choose from in `argmax_choose`.")
    };

    (maximum, value)
}

pub fn sub2ind(dims: &[usize], inds: &[usize]) -> usize {
    let d_it = dims.iter().rev().skip(1);
    let i_it = inds.iter().rev().skip(1);

    d_it.zip(i_it)
        .fold(inds.last().cloned().unwrap(), |acc, (d, i)| i + d * acc)
}

/// Compute the pseudo-inverse of a real matrix using SVD.
pub fn pinv(m: &Array2<f64>) -> Result<Array2<f64>, ndarray_linalg::error::LinalgError> {
    use ndarray::Axis;
    use ndarray_linalg::svd::SVD;

    let m_dim = m.dim();
    let max_dim = m_dim.0.max(m_dim.1);

    m.svd(true, true).map(|(u, s, vt)| {
        // u: (M x M)
        // s: diag{(M x N)} => (max{M, N} x 1)
        // vt: (N x N)
        let u = u.unwrap();
        let vt = vt.unwrap();

        let threshold = f64::EPSILON
            * max_dim as f64
            * s.fold(
                unsafe { *s.uget(0) },
                |acc, &v| {
                    if v > acc {
                        v
                    } else {
                        acc
                    }
                },
            );

        // (max{M, N} x 1)
        let sinv = s
            .mapv(|v| if v > threshold { 1.0 / v } else { 0.0 })
            .insert_axis(Axis(1));

        vt.t().dot(&(&u.t() * &sinv))
    })
}

/// Given a vector containing a partial Cartesian product, and a list of items,
/// return a vector adding the list of items to the partial Cartesian product.
// /// # Example
// ///
// /// ```
// /// use rsrl::utils::partial_cartesian;
// ///
// /// let partial_product = vec![vec![1, 4], vec![1, 5], vec![2, 4], vec![2, 5]];
// /// let items = vec![6, 7];
// /// let next_product = partial_cartesian(partial_product, &items);
// ///
// /// assert_eq!(
// ///     next_product,
// ///     vec![
// ///         vec![1, 4, 6],
// ///         vec![1, 4, 7],
// ///         vec![1, 5, 6],
// ///         vec![1, 5, 7],
// ///         vec![2, 4, 6],
// ///         vec![2, 4, 7],
// ///         vec![2, 5, 6],
// ///         vec![2, 5, 7],
// ///     ]
// /// );
// /// ```
/// Pulled from [here](https://gist.github.com/kylewlacy/115965b40e02a3325558).
pub fn partial_cartesian<T: Clone>(a: Vec<Vec<T>>, b: &[T]) -> Vec<Vec<T>> {
    a.into_iter()
        .flat_map(|xs| {
            b.iter()
                .cloned()
                .map(|y| {
                    let mut vec = xs.clone();
                    vec.push(y);
                    vec
                })
                .collect::<Vec<_>>()
        })
        .collect()
}

/// Computes the Cartesian product of lists[0] * lists[1] * ... * lists[n].
// /// # Example
// ///
// /// ```
// /// use rsrl::utils::cartesian_product;
// ///
// /// let lists = vec![vec![1, 2], vec![4, 5], vec![6, 7]];
// /// let product = cartesian_product(&lists);
// ///
// /// assert_eq!(
// ///     product,
// ///     vec![
// ///         vec![1, 4, 6],
// ///         vec![1, 4, 7],
// ///         vec![1, 5, 6],
// ///         vec![1, 5, 7],
// ///         vec![2, 4, 6],
// ///         vec![2, 4, 7],
// ///         vec![2, 5, 6],
// ///         vec![2, 5, 7],
// ///     ]
// /// );
// /// ```
/// Pulled from [here](https://gist.github.com/kylewlacy/115965b40e02a3325558).
pub fn cartesian_product<T: Clone>(lists: &[Vec<T>]) -> Vec<Vec<T>> {
    match lists.split_first() {
        Some((first, rest)) => {
            let init: Vec<Vec<T>> = first.iter().cloned().map(|n| vec![n]).collect();

            rest.iter()
                .cloned()
                .fold(init, |vec, list| partial_cartesian(vec, &list))
        },
        None => vec![],
    }
}

pub fn compare_floats<T1, I1, T2, I2>(a: I1, b: I2, tol: f64) -> bool
where
    T1: std::borrow::Borrow<f64>,
    I1: IntoIterator<Item = T1>,
    T2: std::borrow::Borrow<f64>,
    I2: IntoIterator<Item = T2>,
{
    a.into_iter()
        .zip(b.into_iter())
        .all(move |(x, y)| (x.borrow() - y.borrow()).abs() < tol)
}

#[cfg(test)]
mod tests {
    use super::{cartesian_product, sub2ind};

    #[test]
    fn test_sub2ind() {
        assert_eq!(sub2ind(&vec![5, 7, 12], &vec![3, 0, 0]), 3);
        assert_eq!(sub2ind(&vec![5, 7, 12], &vec![2, 0, 5]), 177);
        assert_eq!(sub2ind(&vec![5, 7, 12], &vec![2, 5, 5]), 202);
        assert_eq!(sub2ind(&vec![5, 7, 12], &vec![0, 0, 11]), 385);
        assert_eq!(sub2ind(&vec![5, 7, 12], &vec![5, 0, 11]), 390);
    }

    #[test]
    #[should_panic]
    fn test_sub2ind_empty() { sub2ind(&vec![], &vec![]); }

    #[test]
    fn test_cartesian_product() {
        let to_combine = vec![vec![0.0, 1.0, 2.0], vec![7.0, 8.0, 9.0]];

        let combs = cartesian_product(&to_combine);

        assert_eq!(combs[0], vec![0.0, 7.0]);
        assert_eq!(combs[1], vec![0.0, 8.0]);
        assert_eq!(combs[2], vec![0.0, 9.0]);

        assert_eq!(combs[3], vec![1.0, 7.0]);
        assert_eq!(combs[4], vec![1.0, 8.0]);
        assert_eq!(combs[5], vec![1.0, 9.0]);

        assert_eq!(combs[6], vec![2.0, 7.0]);
        assert_eq!(combs[7], vec![2.0, 8.0]);
        assert_eq!(combs[8], vec![2.0, 9.0]);
    }
}
<commit_msg>refactor(utils): remove redundant code<commit_after>#![allow(dead_code)]
use ndarray::Array2;
use rand::{seq::SliceRandom, thread_rng, Rng};
use std::f64;

pub fn argmaxima<I: IntoIterator<Item = f64>>(vals: I) -> (Vec<usize>, f64) {
    let mut max = f64::MIN;
    let mut ixs = vec![];

    for (i, v) in vals.into_iter().enumerate() {
        if (v - max).abs() < 1e-7 {
            ixs.push(i);
        } else if v > max {
            max = v;
            ixs.clear();
            ixs.push(i);
        }
    }

    (ixs, max)
}

pub fn argmax_first<I: IntoIterator<Item = f64>>(vals: I) -> (usize, f64) {
    vals.into_iter().enumerate().fold(
        (0, f64::MIN),
        |(i, x), (j, y)| {
            if y - x > 1e-7 {
                (j, y)
            } else {
                (i, x)
            }
        },
    )
}

pub fn argmax_last<I: IntoIterator<Item = f64>>(vals: I) -> (usize, f64) {
    vals.into_iter().enumerate().fold(
        (0, f64::MIN),
        |(i, x), (j, y)| {
            if y - x > -1e-7 {
                (j, y)
            } else {
                (i, x)
            }
        },
    )
}

pub fn argmax_choose<I: IntoIterator<Item = f64>>(vals: I) -> (usize, f64) {
    let (maxima, value) = argmaxima(vals);

    let maximum = if maxima.len() == 1 {
        maxima[0]
    } else {
        *maxima
            .choose(&mut thread_rng())
            .expect("No valid maxima to choose from in `argmax_choose`.")
    };

    (maximum, value)
}

pub fn argmax_choose_rng<R, I>(rng: &mut R, vals: I) -> (usize, f64)
where
    R: Rng + ?Sized,
    I: IntoIterator<Item = f64>,
{
    let (maxima, value) = argmaxima(vals);

    let maximum = if maxima.len() == 1 {
        maxima[0]
    } else {
        *maxima
            .choose(rng)
            .expect("No valid maxima to choose from in `argmax_choose`.")
    };

    (maximum, value)
}

/// Compute the pseudo-inverse of a real matrix using SVD.
pub fn pinv(m: &Array2<f64>) -> Result<Array2<f64>, ndarray_linalg::error::LinalgError> {
    use ndarray::Axis;
    use ndarray_linalg::svd::SVD;

    let m_dim = m.dim();
    let max_dim = m_dim.0.max(m_dim.1);

    m.svd(true, true).map(|(u, s, vt)| {
        // u: (M x M)
        // s: diag{(M x N)} => (max{M, N} x 1)
        // vt: (N x N)
        let u = u.unwrap();
        let vt = vt.unwrap();

        let threshold = f64::EPSILON
            * max_dim as f64
            * s.fold(
                unsafe { *s.uget(0) },
                |acc, &v| {
                    if v > acc {
                        v
                    } else {
                        acc
                    }
                },
            );

        // (max{M, N} x 1)
        let sinv = s
            .mapv(|v| if v > threshold { 1.0 / v } else { 0.0 })
            .insert_axis(Axis(1));

        vt.t().dot(&(&u.t() * &sinv))
    })
}
<|endoftext|>


<commit_before>#[cfg(unix)]
use libc as errno;
#[cfg(windows)]
use windows::errno;

const ZMQ_HAUSNUMERO: i32 = 156_384_712;

pub const EACCES:           i32 = errno::EACCES;
pub const EADDRINUSE:       i32 = errno::EADDRINUSE;
pub const EAGAIN:           i32 = errno::EAGAIN;
pub const EBUSY:            i32 = errno::EBUSY;
pub const ECONNREFUSED:     i32 = errno::ECONNREFUSED;
pub const EFAULT:           i32 = errno::EFAULT;
pub const EINTR:            i32 = errno::EINTR;
pub const EHOSTUNREACH:     i32 = errno::EHOSTUNREACH;
pub const EINPROGRESS:      i32 = errno::EINPROGRESS;
pub const EINVAL:           i32 = errno::EINVAL;
pub const EMFILE:           i32 = errno::EMFILE;
pub const EMSGSIZE:         i32 = errno::EMSGSIZE;
pub const ENAMETOOLONG:     i32 = errno::ENAMETOOLONG;
pub const ENODEV:           i32 = errno::ENODEV;
pub const ENOENT:           i32 = errno::ENOENT;
pub const ENOMEM:           i32 = errno::ENOMEM;
pub const ENOTCONN:         i32 = errno::ENOTCONN;
pub const ENOTSOCK:         i32 = errno::ENOTSOCK;
pub const EPROTO:           i32 = errno::EPROTO;
pub const EPROTONOSUPPORT:  i32 = errno::EPROTONOSUPPORT;
pub const ENOTSUP:          i32 = errno::ENOTSUP;
pub const ENOBUFS:          i32 = errno::ENOBUFS;
pub const ENETDOWN:         i32 = errno::ENETDOWN;
pub const EADDRNOTAVAIL:    i32 = errno::EADDRNOTAVAIL;

// native zmq error codes
pub const EFSM:             i32 = (ZMQ_HAUSNUMERO + 51);
pub const ENOCOMPATPROTO:   i32 = (ZMQ_HAUSNUMERO + 52);
pub const ETERM:            i32 = (ZMQ_HAUSNUMERO + 53);
pub const EMTHREAD:         i32 = (ZMQ_HAUSNUMERO + 54);

// These may be returned by libzmq if the target platform does not define these
// errno codes.
pub const ENOTSUP_ALT:         i32 = (ZMQ_HAUSNUMERO + 1);
pub const EPROTONOSUPPORT_ALT: i32 = (ZMQ_HAUSNUMERO + 2);
pub const ENOBUFS_ALT:         i32 = (ZMQ_HAUSNUMERO + 3);
pub const ENETDOWN_ALT:        i32 = (ZMQ_HAUSNUMERO + 4);
pub const EADDRINUSE_ALT:      i32 = (ZMQ_HAUSNUMERO + 5);
pub const EADDRNOTAVAIL_ALT:   i32 = (ZMQ_HAUSNUMERO + 6);
pub const ECONNREFUSED_ALT:    i32 = (ZMQ_HAUSNUMERO + 7);
pub const EINPROGRESS_ALT:     i32 = (ZMQ_HAUSNUMERO + 8);
pub const ENOTSOCK_ALT:        i32 = (ZMQ_HAUSNUMERO + 9);
pub const EMSGSIZE_ALT:        i32 = (ZMQ_HAUSNUMERO + 10);
pub const EAFNOSUPPORT_ALT:    i32 = (ZMQ_HAUSNUMERO + 11);
pub const ENETUNREACH_ALT:     i32 = (ZMQ_HAUSNUMERO + 12);
pub const ECONNABORTED_ALT:    i32 = (ZMQ_HAUSNUMERO + 13);
pub const ECONNRESET_ALT:      i32 = (ZMQ_HAUSNUMERO + 14);
pub const ENOTCONN_ALT:        i32 = (ZMQ_HAUSNUMERO + 15);
pub const ETIMEDOUT_ALT:       i32 = (ZMQ_HAUSNUMERO + 16);
pub const EHOSTUNREACH_ALT:    i32 = (ZMQ_HAUSNUMERO + 17);
pub const ENETRESET_ALT:       i32 = (ZMQ_HAUSNUMERO + 18);
<commit_msg>Fix warnings<commit_after>#[cfg(unix)]
use libc as errno;
#[cfg(windows)]
use windows::errno;

const ZMQ_HAUSNUMERO: i32 = 156_384_712;

pub const EACCES:           i32 = errno::EACCES;
pub const EADDRINUSE:       i32 = errno::EADDRINUSE;
pub const EAGAIN:           i32 = errno::EAGAIN;
pub const EBUSY:            i32 = errno::EBUSY;
pub const ECONNREFUSED:     i32 = errno::ECONNREFUSED;
pub const EFAULT:           i32 = errno::EFAULT;
pub const EINTR:            i32 = errno::EINTR;
pub const EHOSTUNREACH:     i32 = errno::EHOSTUNREACH;
pub const EINPROGRESS:      i32 = errno::EINPROGRESS;
pub const EINVAL:           i32 = errno::EINVAL;
pub const EMFILE:           i32 = errno::EMFILE;
pub const EMSGSIZE:         i32 = errno::EMSGSIZE;
pub const ENAMETOOLONG:     i32 = errno::ENAMETOOLONG;
pub const ENODEV:           i32 = errno::ENODEV;
pub const ENOENT:           i32 = errno::ENOENT;
pub const ENOMEM:           i32 = errno::ENOMEM;
pub const ENOTCONN:         i32 = errno::ENOTCONN;
pub const ENOTSOCK:         i32 = errno::ENOTSOCK;
pub const EPROTO:           i32 = errno::EPROTO;
pub const EPROTONOSUPPORT:  i32 = errno::EPROTONOSUPPORT;
pub const ENOTSUP:          i32 = errno::ENOTSUP;
pub const ENOBUFS:          i32 = errno::ENOBUFS;
pub const ENETDOWN:         i32 = errno::ENETDOWN;
pub const EADDRNOTAVAIL:    i32 = errno::EADDRNOTAVAIL;

// native zmq error codes
pub const EFSM:             i32 = ZMQ_HAUSNUMERO + 51;
pub const ENOCOMPATPROTO:   i32 = ZMQ_HAUSNUMERO + 52;
pub const ETERM:            i32 = ZMQ_HAUSNUMERO + 53;
pub const EMTHREAD:         i32 = ZMQ_HAUSNUMERO + 54;

// These may be returned by libzmq if the target platform does not define these
// errno codes.
pub const ENOTSUP_ALT:         i32 = ZMQ_HAUSNUMERO + 1;
pub const EPROTONOSUPPORT_ALT: i32 = ZMQ_HAUSNUMERO + 2;
pub const ENOBUFS_ALT:         i32 = ZMQ_HAUSNUMERO + 3;
pub const ENETDOWN_ALT:        i32 = ZMQ_HAUSNUMERO + 4;
pub const EADDRINUSE_ALT:      i32 = ZMQ_HAUSNUMERO + 5;
pub const EADDRNOTAVAIL_ALT:   i32 = ZMQ_HAUSNUMERO + 6;
pub const ECONNREFUSED_ALT:    i32 = ZMQ_HAUSNUMERO + 7;
pub const EINPROGRESS_ALT:     i32 = ZMQ_HAUSNUMERO + 8;
pub const ENOTSOCK_ALT:        i32 = ZMQ_HAUSNUMERO + 9;
pub const EMSGSIZE_ALT:        i32 = ZMQ_HAUSNUMERO + 10;
pub const EAFNOSUPPORT_ALT:    i32 = ZMQ_HAUSNUMERO + 11;
pub const ENETUNREACH_ALT:     i32 = ZMQ_HAUSNUMERO + 12;
pub const ECONNABORTED_ALT:    i32 = ZMQ_HAUSNUMERO + 13;
pub const ECONNRESET_ALT:      i32 = ZMQ_HAUSNUMERO + 14;
pub const ENOTCONN_ALT:        i32 = ZMQ_HAUSNUMERO + 15;
pub const ETIMEDOUT_ALT:       i32 = ZMQ_HAUSNUMERO + 16;
pub const EHOSTUNREACH_ALT:    i32 = ZMQ_HAUSNUMERO + 17;
pub const ENETRESET_ALT:       i32 = ZMQ_HAUSNUMERO + 18;
<|endoftext|>


<commit_before>// Refactoring part00.rs to using expressions and inherent methods for the NumberOrNothing algebric data type

enum NumberOrNothing {
	Number(i32),
	Nothing,
}

impl NumberOrNothing {
	fn print_min(self){
		match self {
			Nothing => println!("The list is empty"),
			Number(min) => println!("The minimum from the list is {}",min),
		}
	}
	fn print_sum(self){
		match self {
			Nothing => println!("No elements in list"),
			Number(min) => println!("The sum is {}",min),
		}
	}
}

use self::NumberOrNothing::{Number,Nothing};

fn vec_min(vec:Vec<i32>) -> NumberOrNothing {

	//min_i32 is a clousure
	let min_i32 = |a,b| { if a > b {b} else {a} };

	let mut min = Nothing;
	for el in vec {

		match min {
			Nothing => {min = Number(el);},
			Number(n) => {let new_min = min_i32(n,el);min = Number(new_min);},
		}

	}
	min
}

// Exercise 01.1 -----------------------------------------------

fn vec_sum(vec:Vec<i32>) -> NumberOrNothing {
	match vec.len() {
		0 => {Nothing}
		_ => {let mut sum = 0; for i in vec {sum+=i;} Number(sum) }
	}
}
//-------------------------------------------------Exercise 01.1

// Exercise 01.2 -----------------------------------------------

fn vec_print(vec:Vec<i32>) {
	for e in vec {
		println!("{}",e);
	}
}
//-------------------------------------------------Exercise 01.2

fn read_vec(rang:u32) -> Vec<i32> {
	match rang {
		0 => {vec![]},
		_ => {vec![87,4,7,6,5,9,453]},
	}
}

pub fn main(){
	let vec_list = read_vec(8);
	let min = vec_min(vec_list);
	vec_sum(vec![5,4,3,4]).print_sum();
	vec_print(vec![8,9,3,5]);
	min.print_min();
}

<commit_msg>updated exercises<commit_after>// Refactoring part00.rs to using expressions and inherent methods for the NumberOrNothing algebric data type

enum NumberOrNothing {
	Number(i32),
	Nothing,
}

impl NumberOrNothing {
	fn print_min(self){
		match self {
			Nothing => println!("The list is empty"),
			Number(min) => println!("The minimum from the list is {}",min),
		}
	}
	fn print_sum(self){
		match self {
			Nothing => println!("No elements in list"),
			Number(min) => println!("The sum is {}",min),
		}
	}
}

use self::NumberOrNothing::{Number,Nothing};

//fn sqr(a:i32) -> i32 {a*a}
//fn abs(a:i32) -> i32 { if a>=0 {a} else {-a} }

fn vec_min(vec:Vec<i32>) -> NumberOrNothing {

	//min_i32 is a clousure
	let min_i32 = |a,b| { if a > b {b} else {a} };

	let mut min = Nothing;
	for el in vec {

		match min {
			Nothing => {min = Number(el);},
			Number(n) => {let new_min = min_i32(n,el);min = Number(new_min);},
		}

	}
	min
}

// Exercise 01.1 -----------------------------------------------

fn vec_sum(vec:Vec<i32>) -> NumberOrNothing {
	match vec.len() {
		0 => {Nothing}
		_ => {let mut sum = 0; for i in vec {sum+=i;} Number(sum) }
	}
}
//-------------------------------------------------Exercise 01.1

// Exercise 01.2 -----------------------------------------------

fn vec_print(vec:Vec<i32>) {
	for e in vec {
		println!("{}",e);
	}
}
//-------------------------------------------------Exercise 01.2

fn read_vec(rang:u32) -> Vec<i32> {
	match rang {
		0 => {vec![]},
		_ => {vec![87,4,7,6,5,9,453]},
	}
}

pub fn main(){
	let vec_list = read_vec(8);
	let min = vec_min(vec_list);
	vec_sum(vec![5,4,3,4]).print_sum();
	vec_print(vec![8,9,3,5]);
	min.print_min();
}

<|endoftext|>


<commit_before>//! An analysis to determine which locals require allocas and
//! which do not.

use super::FunctionCx;
use crate::traits::*;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::traversal;
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Location, TerminatorKind};
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_target::abi::LayoutOf;

pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
    fx: &FunctionCx<'a, 'tcx, Bx>,
) -> BitSet<mir::Local> {
    let mir = fx.mir;
    let mut analyzer = LocalAnalyzer::new(fx);

    for (bb, data) in mir.basic_blocks().iter_enumerated() {
        analyzer.visit_basic_block_data(bb, data);
    }

    for (local, decl) in mir.local_decls.iter_enumerated() {
        let ty = fx.monomorphize(decl.ty);
        debug!("local {:?} has type `{}`", local, ty);
        let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
        if fx.cx.is_backend_immediate(layout) {
            // These sorts of types are immediates that we can store
            // in an Value without an alloca.
        } else if fx.cx.is_backend_scalar_pair(layout) {
            // We allow pairs and uses of any of their 2 fields.
        } else {
            // These sorts of types require an alloca. Note that
            // is_llvm_immediate() may *still* be true, particularly
            // for newtypes, but we currently force some types
            // (e.g., structs) into an alloca unconditionally, just so
            // that we don't have to deal with having two pathways
            // (gep vs extractvalue etc).
            analyzer.not_ssa(local);
        }
    }

    analyzer.non_ssa_locals
}

struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
    fx: &'mir FunctionCx<'a, 'tcx, Bx>,
    dominators: Dominators<mir::BasicBlock>,
    non_ssa_locals: BitSet<mir::Local>,
    // The location of the first visited direct assignment to each
    // local, or an invalid location (out of bounds `block` index).
    first_assignment: IndexVec<mir::Local, Location>,
}

impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
    fn new(fx: &'mir FunctionCx<'a, 'tcx, Bx>) -> Self {
        let invalid_location = mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();
        let dominators = fx.mir.dominators();
        let mut analyzer = LocalAnalyzer {
            fx,
            dominators,
            non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()),
            first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls),
        };

        // Arguments get assigned to by means of the function being called
        for arg in fx.mir.args_iter() {
            analyzer.first_assignment[arg] = mir::START_BLOCK.start_location();
        }

        analyzer
    }

    fn first_assignment(&self, local: mir::Local) -> Option<Location> {
        let location = self.first_assignment[local];
        if location.block.index() < self.fx.mir.basic_blocks().len() {
            Some(location)
        } else {
            None
        }
    }

    fn not_ssa(&mut self, local: mir::Local) {
        debug!("marking {:?} as non-SSA", local);
        self.non_ssa_locals.insert(local);
    }

    fn assign(&mut self, local: mir::Local, location: Location) {
        if self.first_assignment(local).is_some() {
            self.not_ssa(local);
        } else {
            self.first_assignment[local] = location;
        }
    }

    fn process_place(
        &mut self,
        place_ref: &mir::PlaceRef<'tcx>,
        context: PlaceContext,
        location: Location,
    ) {
        let cx = self.fx.cx;

        if let Some((place_base, elem)) = place_ref.last_projection() {
            let mut base_context = if context.is_mutating_use() {
                PlaceContext::MutatingUse(MutatingUseContext::Projection)
            } else {
                PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
            };

            // Allow uses of projections that are ZSTs or from scalar fields.
            let is_consume = matches!(
                context,
                PlaceContext::NonMutatingUse(
                    NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
                )
            );
            if is_consume {
                let base_ty = place_base.ty(self.fx.mir, cx.tcx());
                let base_ty = self.fx.monomorphize(base_ty);

                // ZSTs don't require any actual memory access.
                let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(elem)).ty;
                let span = self.fx.mir.local_decls[place_ref.local].source_info.span;
                if cx.spanned_layout_of(elem_ty, span).is_zst() {
                    return;
                }

                if let mir::ProjectionElem::Field(..) = elem {
                    let layout = cx.spanned_layout_of(base_ty.ty, span);
                    if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
                        // Recurse with the same context, instead of `Projection`,
                        // potentially stopping at non-operand projections,
                        // which would trigger `not_ssa` on locals.
                        base_context = context;
                    }
                }
            }

            if let mir::ProjectionElem::Deref = elem {
                // Deref projections typically only read the pointer.
                base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
            }

            self.process_place(&place_base, base_context, location);
            // HACK(eddyb) this emulates the old `visit_projection_elem`, this
            // entire `visit_place`-like `process_place` method should be rewritten,
            // now that we have moved to the "slice of projections" representation.
            if let mir::ProjectionElem::Index(local) = elem {
                self.visit_local(
                    &local,
                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
                    location,
                );
            }
        } else {
            self.visit_local(&place_ref.local, context, location);
        }
    }
}

impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
    for LocalAnalyzer<'mir, 'a, 'tcx, Bx>
{
    fn visit_assign(
        &mut self,
        place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: Location,
    ) {
        debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);

        if let Some(index) = place.as_local() {
            self.assign(index, location);
            let decl_span = self.fx.mir.local_decls[index].source_info.span;
            if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
                self.not_ssa(index);
            }
        } else {
            self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location);
        }

        self.visit_rvalue(rvalue, location);
    }

    fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
        debug!("visit_place(place={:?}, context={:?})", place, context);
        self.process_place(&place.as_ref(), context, location);
    }

    fn visit_local(&mut self, &local: &mir::Local, context: PlaceContext, location: Location) {
        match context {
            PlaceContext::MutatingUse(MutatingUseContext::Call)
            | PlaceContext::MutatingUse(MutatingUseContext::Yield) => {
                self.assign(local, location);
            }

            PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}

            PlaceContext::NonMutatingUse(
                NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
            ) => {
                // Reads from uninitialized variables (e.g., in dead code, after
                // optimizations) require locals to be in (uninitialized) memory.
                // N.B., there can be uninitialized reads of a local visited after
                // an assignment to that local, if they happen on disjoint paths.
                let ssa_read = match self.first_assignment(local) {
                    Some(assignment_location) => {
                        assignment_location.dominates(location, &self.dominators)
                    }
                    None => {
                        debug!("No first assignment found for {:?}", local);
                        // We have not seen any assignment to the local yet,
                        // but before marking not_ssa, check if it is a ZST,
                        // in which case we don't need to initialize the local.
                        let ty = self.fx.mir.local_decls[local].ty;
                        let ty = self.fx.monomorphize(ty);

                        let is_zst = self.fx.cx.layout_of(ty).is_zst();
                        debug!("is_zst: {}", is_zst);
                        is_zst
                    }
                };
                if !ssa_read {
                    self.not_ssa(local);
                }
            }

            PlaceContext::MutatingUse(
                MutatingUseContext::Store
                | MutatingUseContext::AsmOutput
                | MutatingUseContext::Borrow
                | MutatingUseContext::AddressOf
                | MutatingUseContext::Projection,
            )
            | PlaceContext::NonMutatingUse(
                NonMutatingUseContext::Inspect
                | NonMutatingUseContext::SharedBorrow
                | NonMutatingUseContext::UniqueBorrow
                | NonMutatingUseContext::ShallowBorrow
                | NonMutatingUseContext::AddressOf
                | NonMutatingUseContext::Projection,
            ) => {
                self.not_ssa(local);
            }

            PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
                let ty = self.fx.mir.local_decls[local].ty;
                let ty = self.fx.monomorphize(ty);

                // Only need the place if we're actually dropping it.
                if self.fx.cx.type_needs_drop(ty) {
                    self.not_ssa(local);
                }
            }
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CleanupKind {
    NotCleanup,
    Funclet,
    Internal { funclet: mir::BasicBlock },
}

impl CleanupKind {
    pub fn funclet_bb(self, for_bb: mir::BasicBlock) -> Option<mir::BasicBlock> {
        match self {
            CleanupKind::NotCleanup => None,
            CleanupKind::Funclet => Some(for_bb),
            CleanupKind::Internal { funclet } => Some(funclet),
        }
    }
}

pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKind> {
    fn discover_masters<'tcx>(
        result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
        mir: &mir::Body<'tcx>,
    ) {
        for (bb, data) in mir.basic_blocks().iter_enumerated() {
            match data.terminator().kind {
                TerminatorKind::Goto { .. }
                | TerminatorKind::Resume
                | TerminatorKind::Abort
                | TerminatorKind::Return
                | TerminatorKind::GeneratorDrop
                | TerminatorKind::Unreachable
                | TerminatorKind::SwitchInt { .. }
                | TerminatorKind::Yield { .. }
                | TerminatorKind::FalseEdge { .. }
                | TerminatorKind::FalseUnwind { .. }
                | TerminatorKind::InlineAsm { .. } => { /* nothing to do */ }
                TerminatorKind::Call { cleanup: unwind, .. }
                | TerminatorKind::Assert { cleanup: unwind, .. }
                | TerminatorKind::DropAndReplace { unwind, .. }
                | TerminatorKind::Drop { unwind, .. } => {
                    if let Some(unwind) = unwind {
                        debug!(
                            "cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
                            bb, data, unwind
                        );
                        result[unwind] = CleanupKind::Funclet;
                    }
                }
            }
        }
    }

    fn propagate<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>, mir: &mir::Body<'tcx>) {
        let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks());

        let mut set_successor = |funclet: mir::BasicBlock, succ| match funclet_succs[funclet] {
            ref mut s @ None => {
                debug!("set_successor: updating successor of {:?} to {:?}", funclet, succ);
                *s = Some(succ);
            }
            Some(s) => {
                if s != succ {
                    span_bug!(
                        mir.span,
                        "funclet {:?} has 2 parents - {:?} and {:?}",
                        funclet,
                        s,
                        succ
                    );
                }
            }
        };

        for (bb, data) in traversal::reverse_postorder(mir) {
            let funclet = match result[bb] {
                CleanupKind::NotCleanup => continue,
                CleanupKind::Funclet => bb,
                CleanupKind::Internal { funclet } => funclet,
            };

            debug!(
                "cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",
                bb, data, result[bb], funclet
            );

            for &succ in data.terminator().successors() {
                let kind = result[succ];
                debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", funclet, succ, kind);
                match kind {
                    CleanupKind::NotCleanup => {
                        result[succ] = CleanupKind::Internal { funclet };
                    }
                    CleanupKind::Funclet => {
                        if funclet != succ {
                            set_successor(funclet, succ);
                        }
                    }
                    CleanupKind::Internal { funclet: succ_funclet } => {
                        if funclet != succ_funclet {
                            // `succ` has 2 different funclet going into it, so it must
                            // be a funclet by itself.

                            debug!(
                                "promoting {:?} to a funclet and updating {:?}",
                                succ, succ_funclet
                            );
                            result[succ] = CleanupKind::Funclet;
                            set_successor(succ_funclet, succ);
                            set_successor(funclet, succ);
                        }
                    }
                }
            }
        }
    }

    let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks());

    discover_masters(&mut result, mir);
    propagate(&mut result, mir);
    debug!("cleanup_kinds: result={:?}", result);
    result
}
<commit_msg>Use preorder traversal when checking for SSA locals<commit_after>//! An analysis to determine which locals require allocas and
//! which do not.

use super::FunctionCx;
use crate::traits::*;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::traversal;
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Location, TerminatorKind};
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_target::abi::LayoutOf;

pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
    fx: &FunctionCx<'a, 'tcx, Bx>,
) -> BitSet<mir::Local> {
    let mir = fx.mir;
    let mut analyzer = LocalAnalyzer::new(fx);

    // If there exists a local definition that dominates all uses of that local,
    // the definition should be visited first. Traverse blocks in preorder which
    // is a topological sort of dominance partial order.
    for (bb, data) in traversal::preorder(&mir) {
        analyzer.visit_basic_block_data(bb, data);
    }

    for (local, decl) in mir.local_decls.iter_enumerated() {
        let ty = fx.monomorphize(decl.ty);
        debug!("local {:?} has type `{}`", local, ty);
        let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
        if fx.cx.is_backend_immediate(layout) {
            // These sorts of types are immediates that we can store
            // in an Value without an alloca.
        } else if fx.cx.is_backend_scalar_pair(layout) {
            // We allow pairs and uses of any of their 2 fields.
        } else {
            // These sorts of types require an alloca. Note that
            // is_llvm_immediate() may *still* be true, particularly
            // for newtypes, but we currently force some types
            // (e.g., structs) into an alloca unconditionally, just so
            // that we don't have to deal with having two pathways
            // (gep vs extractvalue etc).
            analyzer.not_ssa(local);
        }
    }

    analyzer.non_ssa_locals
}

struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
    fx: &'mir FunctionCx<'a, 'tcx, Bx>,
    dominators: Dominators<mir::BasicBlock>,
    non_ssa_locals: BitSet<mir::Local>,
    // The location of the first visited direct assignment to each
    // local, or an invalid location (out of bounds `block` index).
    first_assignment: IndexVec<mir::Local, Location>,
}

impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
    fn new(fx: &'mir FunctionCx<'a, 'tcx, Bx>) -> Self {
        let invalid_location = mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();
        let dominators = fx.mir.dominators();
        let mut analyzer = LocalAnalyzer {
            fx,
            dominators,
            non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()),
            first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls),
        };

        // Arguments get assigned to by means of the function being called
        for arg in fx.mir.args_iter() {
            analyzer.first_assignment[arg] = mir::START_BLOCK.start_location();
        }

        analyzer
    }

    fn first_assignment(&self, local: mir::Local) -> Option<Location> {
        let location = self.first_assignment[local];
        if location.block.index() < self.fx.mir.basic_blocks().len() {
            Some(location)
        } else {
            None
        }
    }

    fn not_ssa(&mut self, local: mir::Local) {
        debug!("marking {:?} as non-SSA", local);
        self.non_ssa_locals.insert(local);
    }

    fn assign(&mut self, local: mir::Local, location: Location) {
        if self.first_assignment(local).is_some() {
            self.not_ssa(local);
        } else {
            self.first_assignment[local] = location;
        }
    }

    fn process_place(
        &mut self,
        place_ref: &mir::PlaceRef<'tcx>,
        context: PlaceContext,
        location: Location,
    ) {
        let cx = self.fx.cx;

        if let Some((place_base, elem)) = place_ref.last_projection() {
            let mut base_context = if context.is_mutating_use() {
                PlaceContext::MutatingUse(MutatingUseContext::Projection)
            } else {
                PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
            };

            // Allow uses of projections that are ZSTs or from scalar fields.
            let is_consume = matches!(
                context,
                PlaceContext::NonMutatingUse(
                    NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
                )
            );
            if is_consume {
                let base_ty = place_base.ty(self.fx.mir, cx.tcx());
                let base_ty = self.fx.monomorphize(base_ty);

                // ZSTs don't require any actual memory access.
                let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(elem)).ty;
                let span = self.fx.mir.local_decls[place_ref.local].source_info.span;
                if cx.spanned_layout_of(elem_ty, span).is_zst() {
                    return;
                }

                if let mir::ProjectionElem::Field(..) = elem {
                    let layout = cx.spanned_layout_of(base_ty.ty, span);
                    if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
                        // Recurse with the same context, instead of `Projection`,
                        // potentially stopping at non-operand projections,
                        // which would trigger `not_ssa` on locals.
                        base_context = context;
                    }
                }
            }

            if let mir::ProjectionElem::Deref = elem {
                // Deref projections typically only read the pointer.
                base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
            }

            self.process_place(&place_base, base_context, location);
            // HACK(eddyb) this emulates the old `visit_projection_elem`, this
            // entire `visit_place`-like `process_place` method should be rewritten,
            // now that we have moved to the "slice of projections" representation.
            if let mir::ProjectionElem::Index(local) = elem {
                self.visit_local(
                    &local,
                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
                    location,
                );
            }
        } else {
            self.visit_local(&place_ref.local, context, location);
        }
    }
}

impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
    for LocalAnalyzer<'mir, 'a, 'tcx, Bx>
{
    fn visit_assign(
        &mut self,
        place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: Location,
    ) {
        debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);

        if let Some(index) = place.as_local() {
            self.assign(index, location);
            let decl_span = self.fx.mir.local_decls[index].source_info.span;
            if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
                self.not_ssa(index);
            }
        } else {
            self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location);
        }

        self.visit_rvalue(rvalue, location);
    }

    fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
        debug!("visit_place(place={:?}, context={:?})", place, context);
        self.process_place(&place.as_ref(), context, location);
    }

    fn visit_local(&mut self, &local: &mir::Local, context: PlaceContext, location: Location) {
        match context {
            PlaceContext::MutatingUse(MutatingUseContext::Call)
            | PlaceContext::MutatingUse(MutatingUseContext::Yield) => {
                self.assign(local, location);
            }

            PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}

            PlaceContext::NonMutatingUse(
                NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
            ) => {
                // Reads from uninitialized variables (e.g., in dead code, after
                // optimizations) require locals to be in (uninitialized) memory.
                // N.B., there can be uninitialized reads of a local visited after
                // an assignment to that local, if they happen on disjoint paths.
                let ssa_read = match self.first_assignment(local) {
                    Some(assignment_location) => {
                        assignment_location.dominates(location, &self.dominators)
                    }
                    None => {
                        debug!("No first assignment found for {:?}", local);
                        // We have not seen any assignment to the local yet,
                        // but before marking not_ssa, check if it is a ZST,
                        // in which case we don't need to initialize the local.
                        let ty = self.fx.mir.local_decls[local].ty;
                        let ty = self.fx.monomorphize(ty);

                        let is_zst = self.fx.cx.layout_of(ty).is_zst();
                        debug!("is_zst: {}", is_zst);
                        is_zst
                    }
                };
                if !ssa_read {
                    self.not_ssa(local);
                }
            }

            PlaceContext::MutatingUse(
                MutatingUseContext::Store
                | MutatingUseContext::AsmOutput
                | MutatingUseContext::Borrow
                | MutatingUseContext::AddressOf
                | MutatingUseContext::Projection,
            )
            | PlaceContext::NonMutatingUse(
                NonMutatingUseContext::Inspect
                | NonMutatingUseContext::SharedBorrow
                | NonMutatingUseContext::UniqueBorrow
                | NonMutatingUseContext::ShallowBorrow
                | NonMutatingUseContext::AddressOf
                | NonMutatingUseContext::Projection,
            ) => {
                self.not_ssa(local);
            }

            PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
                let ty = self.fx.mir.local_decls[local].ty;
                let ty = self.fx.monomorphize(ty);

                // Only need the place if we're actually dropping it.
                if self.fx.cx.type_needs_drop(ty) {
                    self.not_ssa(local);
                }
            }
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CleanupKind {
    NotCleanup,
    Funclet,
    Internal { funclet: mir::BasicBlock },
}

impl CleanupKind {
    pub fn funclet_bb(self, for_bb: mir::BasicBlock) -> Option<mir::BasicBlock> {
        match self {
            CleanupKind::NotCleanup => None,
            CleanupKind::Funclet => Some(for_bb),
            CleanupKind::Internal { funclet } => Some(funclet),
        }
    }
}

pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKind> {
    fn discover_masters<'tcx>(
        result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
        mir: &mir::Body<'tcx>,
    ) {
        for (bb, data) in mir.basic_blocks().iter_enumerated() {
            match data.terminator().kind {
                TerminatorKind::Goto { .. }
                | TerminatorKind::Resume
                | TerminatorKind::Abort
                | TerminatorKind::Return
                | TerminatorKind::GeneratorDrop
                | TerminatorKind::Unreachable
                | TerminatorKind::SwitchInt { .. }
                | TerminatorKind::Yield { .. }
                | TerminatorKind::FalseEdge { .. }
                | TerminatorKind::FalseUnwind { .. }
                | TerminatorKind::InlineAsm { .. } => { /* nothing to do */ }
                TerminatorKind::Call { cleanup: unwind, .. }
                | TerminatorKind::Assert { cleanup: unwind, .. }
                | TerminatorKind::DropAndReplace { unwind, .. }
                | TerminatorKind::Drop { unwind, .. } => {
                    if let Some(unwind) = unwind {
                        debug!(
                            "cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
                            bb, data, unwind
                        );
                        result[unwind] = CleanupKind::Funclet;
                    }
                }
            }
        }
    }

    fn propagate<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>, mir: &mir::Body<'tcx>) {
        let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks());

        let mut set_successor = |funclet: mir::BasicBlock, succ| match funclet_succs[funclet] {
            ref mut s @ None => {
                debug!("set_successor: updating successor of {:?} to {:?}", funclet, succ);
                *s = Some(succ);
            }
            Some(s) => {
                if s != succ {
                    span_bug!(
                        mir.span,
                        "funclet {:?} has 2 parents - {:?} and {:?}",
                        funclet,
                        s,
                        succ
                    );
                }
            }
        };

        for (bb, data) in traversal::reverse_postorder(mir) {
            let funclet = match result[bb] {
                CleanupKind::NotCleanup => continue,
                CleanupKind::Funclet => bb,
                CleanupKind::Internal { funclet } => funclet,
            };

            debug!(
                "cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",
                bb, data, result[bb], funclet
            );

            for &succ in data.terminator().successors() {
                let kind = result[succ];
                debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", funclet, succ, kind);
                match kind {
                    CleanupKind::NotCleanup => {
                        result[succ] = CleanupKind::Internal { funclet };
                    }
                    CleanupKind::Funclet => {
                        if funclet != succ {
                            set_successor(funclet, succ);
                        }
                    }
                    CleanupKind::Internal { funclet: succ_funclet } => {
                        if funclet != succ_funclet {
                            // `succ` has 2 different funclet going into it, so it must
                            // be a funclet by itself.

                            debug!(
                                "promoting {:?} to a funclet and updating {:?}",
                                succ, succ_funclet
                            );
                            result[succ] = CleanupKind::Funclet;
                            set_successor(succ_funclet, succ);
                            set_successor(funclet, succ);
                        }
                    }
                }
            }
        }
    }

    let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks());

    discover_masters(&mut result, mir);
    propagate(&mut result, mir);
    debug!("cleanup_kinds: result={:?}", result);
    result
}
<|endoftext|>


<commit_before>// Non-conventional componentwise operators.

use num::{Signed, Zero};
use std::ops::{Add, Mul};

use alga::general::{ClosedDiv, ClosedMul};

use base::allocator::{Allocator, SameShapeAllocator};
use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::Dim;
use base::storage::{Storage, StorageMut};
use base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar};

/// The type of the result of a matrix componentwise operation.
pub type MatrixComponentOp<N, R1, C1, R2, C2> = MatrixSum<N, R1, C1, R2, C2>;

impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
    /// Computes the componentwise absolute value.
    #[inline]
    pub fn abs(&self) -> MatrixMN<N, R, C>
    where
        N: Signed,
        DefaultAllocator: Allocator<N, R, C>,
    {
        let mut res = self.clone_owned();

        for e in res.iter_mut() {
            *e = e.abs();
        }

        res
    }

    // FIXME: add other operators like component_ln, component_pow, etc. ?
}

macro_rules! component_binop_impl(
    ($($binop: ident, $binop_mut: ident, $binop_assign: ident, $cmpy: ident, $Trait: ident . $op: ident . $op_assign: ident, $desc:expr, $desc_cmpy:expr, $desc_mut:expr);* $(;)*) => {$(
        impl<N: Scalar, R1: Dim, C1: Dim, SA: Storage<N, R1, C1>> Matrix<N, R1, C1, SA> {
            #[doc = $desc]
            #[inline]
            pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixComponentOp<N, R1, C1, R2, C2>
                where N: $Trait,
                      R2: Dim, C2: Dim,
                      SB: Storage<N, R2, C2>,
                      DefaultAllocator: SameShapeAllocator<N, R1, C1, R2, C2>,
                      ShapeConstraint:  SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {

                assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
                let mut res = self.clone_owned_sum();

                for j in 0 .. res.ncols() {
                    for i in 0 .. res.nrows() {
                        unsafe {
                            res.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j));
                        }
                    }
                }

                res
            }
        }

        impl<N: Scalar, R1: Dim, C1: Dim, SA: StorageMut<N, R1, C1>> Matrix<N, R1, C1, SA> {
            // componentwise binop plus Y.
            #[doc = $desc_cmpy]
            #[inline]
            pub fn $cmpy<R2, C2, SB, R3, C3, SC>(&mut self, alpha: N, a: &Matrix<N, R2, C2, SB>, b: &Matrix<N, R3, C3, SC>, beta: N)
                where N: $Trait + Zero + Mul<N, Output = N> + Add<N, Output = N>,
                      R2: Dim, C2: Dim,
                      R3: Dim, C3: Dim,
                      SB: Storage<N, R2, C2>,
                      SC: Storage<N, R3, C3>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
                                       SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
                assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
                assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions.");

                if beta.is_zero() {
                    for j in 0 .. self.ncols() {
                        for i in 0 .. self.nrows() {
                            unsafe {
                                let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j));
                                *self.get_unchecked_mut(i, j) = res;
                            }
                        }
                    }
                }
                else {
                    for j in 0 .. self.ncols() {
                        for i in 0 .. self.nrows() {
                            unsafe {
                                let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j));
                                *self.get_unchecked_mut(i, j) = beta * *self.get_unchecked(i, j) + res;
                            }
                        }
                    }
                }
            }

            #[doc = $desc_mut]
            #[inline]
            pub fn $binop_assign<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
                where N: $Trait,
                      R2: Dim,
                      C2: Dim,
                      SB: Storage<N, R2, C2>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {

                assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");

                for j in 0 .. self.ncols() {
                    for i in 0 .. self.nrows() {
                        unsafe {
                            self.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j));
                        }
                    }
                }
            }

            #[doc = $desc_mut]
            #[inline]
            #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")]
            pub fn $binop_mut<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
                where N: $Trait,
                      R2: Dim,
                      C2: Dim,
                      SB: Storage<N, R2, C2>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
                self.$binop_assign(rhs)
            }
        }
    )*}
);

component_binop_impl!(
    component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign,
    "Componentwise matrix multiplication.",
    "Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`.",
    "Inplace componentwise matrix multiplication.";
    component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign,
    "Componentwise matrix division.",
    "Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`.",
    "Inplace componentwise matrix division.";
    // FIXME: add other operators like bitshift, etc. ?
);
<commit_msg>Add doc-tests for componentwise operations.<commit_after>// Non-conventional componentwise operators.

use num::{Signed, Zero};
use std::ops::{Add, Mul};

use alga::general::{ClosedDiv, ClosedMul};

use base::allocator::{Allocator, SameShapeAllocator};
use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::Dim;
use base::storage::{Storage, StorageMut};
use base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar};

/// The type of the result of a matrix component-wise operation.
pub type MatrixComponentOp<N, R1, C1, R2, C2> = MatrixSum<N, R1, C1, R2, C2>;

impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
    /// Computes the component-wise absolute value.
    ///
    /// # Example
    ///
    /// ```
    /// # use nalgebra::Matrix2;
    /// let a = Matrix2::new(0.0, 1.0,
    ///                      -2.0, -3.0);
    /// assert_eq!(a.abs(), Matrix2::new(0.0, 1.0, 2.0, 3.0))
    /// ```
    #[inline]
    pub fn abs(&self) -> MatrixMN<N, R, C>
    where
        N: Signed,
        DefaultAllocator: Allocator<N, R, C>,
    {
        let mut res = self.clone_owned();

        for e in res.iter_mut() {
            *e = e.abs();
        }

        res
    }

    // FIXME: add other operators like component_ln, component_pow, etc. ?
}

macro_rules! component_binop_impl(
    ($($binop: ident, $binop_mut: ident, $binop_assign: ident, $cmpy: ident, $Trait: ident . $op: ident . $op_assign: ident, $desc:expr, $desc_cmpy:expr, $desc_mut:expr);* $(;)*) => {$(
        impl<N: Scalar, R1: Dim, C1: Dim, SA: Storage<N, R1, C1>> Matrix<N, R1, C1, SA> {
            #[doc = $desc]
            #[inline]
            pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixComponentOp<N, R1, C1, R2, C2>
                where N: $Trait,
                      R2: Dim, C2: Dim,
                      SB: Storage<N, R2, C2>,
                      DefaultAllocator: SameShapeAllocator<N, R1, C1, R2, C2>,
                      ShapeConstraint:  SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {

                assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
                let mut res = self.clone_owned_sum();

                for j in 0 .. res.ncols() {
                    for i in 0 .. res.nrows() {
                        unsafe {
                            res.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j));
                        }
                    }
                }

                res
            }
        }

        impl<N: Scalar, R1: Dim, C1: Dim, SA: StorageMut<N, R1, C1>> Matrix<N, R1, C1, SA> {
            // componentwise binop plus Y.
            #[doc = $desc_cmpy]
            #[inline]
            pub fn $cmpy<R2, C2, SB, R3, C3, SC>(&mut self, alpha: N, a: &Matrix<N, R2, C2, SB>, b: &Matrix<N, R3, C3, SC>, beta: N)
                where N: $Trait + Zero + Mul<N, Output = N> + Add<N, Output = N>,
                      R2: Dim, C2: Dim,
                      R3: Dim, C3: Dim,
                      SB: Storage<N, R2, C2>,
                      SC: Storage<N, R3, C3>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
                                       SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
                assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
                assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions.");

                if beta.is_zero() {
                    for j in 0 .. self.ncols() {
                        for i in 0 .. self.nrows() {
                            unsafe {
                                let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j));
                                *self.get_unchecked_mut(i, j) = res;
                            }
                        }
                    }
                }
                else {
                    for j in 0 .. self.ncols() {
                        for i in 0 .. self.nrows() {
                            unsafe {
                                let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j));
                                *self.get_unchecked_mut(i, j) = beta * *self.get_unchecked(i, j) + res;
                            }
                        }
                    }
                }
            }

            #[doc = $desc_mut]
            #[inline]
            pub fn $binop_assign<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
                where N: $Trait,
                      R2: Dim,
                      C2: Dim,
                      SB: Storage<N, R2, C2>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {

                assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");

                for j in 0 .. self.ncols() {
                    for i in 0 .. self.nrows() {
                        unsafe {
                            self.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j));
                        }
                    }
                }
            }

            #[doc = $desc_mut]
            #[inline]
            #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")]
            pub fn $binop_mut<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
                where N: $Trait,
                      R2: Dim,
                      C2: Dim,
                      SB: Storage<N, R2, C2>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
                self.$binop_assign(rhs)
            }
        }
    )*}
);

component_binop_impl!(
    component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign,
    r"
    Componentwise matrix or vector multiplication.

    # Example

    ```
    # use nalgebra::Matrix2;
    let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);

    assert_eq!(a.component_mul(&b), expected);
    ```
    ",
    r"
    Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = (a.component_mul(&b) * 5.0) + m * 10.0;

    m.cmpy(5.0, &a, &b, 10.0);
    assert_eq!(m, expected);
    ```
    ",
    r"
    Inplace componentwise matrix or vector multiplication.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);

    a.component_mul_assign(&b);

    assert_eq!(a, expected);
    ```
    ";
    component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign,
    r"
    Componentwise matrix or vector division.

    # Example

    ```
    # use nalgebra::Matrix2;
    let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);

    assert_eq!(a.component_div(&b), expected);
    ```
    ",
    r"
    Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let a = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = (a.component_div(&b) * 5.0) + m * 10.0;

    m.cdpy(5.0, &a, &b, 10.0);
    assert_eq!(m, expected);
    ```
    ",
    r"
    Inplace componentwise matrix or vector division.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);

    a.component_div_assign(&b);

    assert_eq!(a, expected);
    ```
    ";
    // FIXME: add other operators like bitshift, etc. ?
);
<|endoftext|>