<commit_before>//! Contains the definitions of the various traits used in this crate.

use std::ops::Add;

/// Implemented for primitive pixel types.
pub trait Primitive: Clone + Add { }

impl Primitive for i8 { }
impl Primitive for u8 { }
impl Primitive for i16 { }
impl Primitive for u16 { }
impl Primitive for i32 { }
impl Primitive for u32 { }
impl Primitive for i64 { }
impl Primitive for u64 { }
impl Primitive for f32 { }
impl Primitive for f64 { }

/// This trait must be implemented for the types you want to store in an image.
pub trait Pixel: Clone + Add { }

impl<P> Pixel for P where P: Primitive { }
<commit_msg>Implement Primitive for isize/usize<commit_after>//! Contains the definitions of the various traits used in this crate.

use std::ops::Add;

/// Implemented for primitive pixel types.
pub trait Primitive: Clone + Add { }

impl Primitive for i8 { }
impl Primitive for u8 { }
impl Primitive for i16 { }
impl Primitive for u16 { }
impl Primitive for i32 { }
impl Primitive for u32 { }
impl Primitive for i64 { }
impl Primitive for u64 { }
impl Primitive for usize { }
impl Primitive for isize { }
impl Primitive for f32 { }
impl Primitive for f64 { }

/// This trait must be implemented for the types you want to store in an image.
pub trait Pixel: Clone + Add { }

impl<P> Pixel for P where P: Primitive { }
<|endoftext|>


<commit_before>use ffi;
use face::Face;

#[derive(Copy, Clone)]
pub struct TrueTypeOS2Table {
    raw: ffi::TT_OS2_Internal
}

impl TrueTypeOS2Table  {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    pub fn from_face(face: &mut Face) -> Option<Self> {
        unsafe {
            let os2 = ffi::FT_Get_Sfnt_Table(face.raw_mut() as *mut ffi::FT_FaceRec, ffi::ft_sfnt_os2) as ffi::TT_OS2_Internal;
            if !os2.is_null() && (*os2).version != 0xffff {
                Some(TrueTypeOS2Table {
                    raw: os2
                })
            } else {
                None
            }
        }
    }

    #[inline(always)]
    pub fn version(&self) -> ffi::FT_UShort {
        unsafe {
            (*self.raw).version
        }
    }

    #[inline(always)]
    pub fn avg_char_width(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).xAvgCharWidth
        }
    }

    #[inline(always)]
    pub fn us_weight_class(&self) -> ffi::FT_UShort {
        unsafe {
            (*self.raw).usWeightClass
        }
    }

    #[inline(always)]
    pub fn us_width_class(&self) -> ffi::FT_UShort {
        unsafe {
            (*self.raw).usWidthClass
        }
    }

    #[inline(always)]
    pub fn fs_type(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).fsType
        }
    }

    #[inline(always)]
    pub fn y_subscript_x_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySubscriptXSize
        }
    }

    #[inline(always)]
    pub fn y_subscript_y_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySubscriptYSize
        }
    }

    #[inline(always)]
    pub fn y_subscript_x_offset(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySubscriptXOffset
        }
    }

    #[inline(always)]
    pub fn y_subscript_y_offset(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySubscriptYOffset
        }
    }

    #[inline(always)]
    pub fn y_superscript_x_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySuperscriptXSize
        }
    }

    #[inline(always)]
    pub fn y_superscript_y_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySuperscriptYSize
        }
    }

    #[inline(always)]
    pub fn y_superscript_x_offset(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySuperscriptXOffset
        }
    }

    #[inline(always)]
    pub fn y_superscript_y_offset(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySuperscriptYOffset
        }
    }

    #[inline(always)]
    pub fn y_strikeout_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).yStrikeoutSize
        }
    }

    #[inline(always)]
    pub fn y_strikeout_position(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).yStrikeoutPosition
        }
    }

    #[inline(always)]
    pub fn s_family_class(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).sFamilyClass
        }
    }

    #[inline(always)]
    pub fn x_height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).sxHeight
        }
    }
}
<commit_msg>Allow TrueTypeOS2Table::from_face on all OSes<commit_after>use ffi;
use face::Face;

#[derive(Copy, Clone)]
pub struct TrueTypeOS2Table {
    raw: ffi::TT_OS2_Internal
}

impl TrueTypeOS2Table  {
    pub fn from_face(face: &mut Face) -> Option<Self> {
        unsafe {
            let os2 = ffi::FT_Get_Sfnt_Table(face.raw_mut() as *mut ffi::FT_FaceRec, ffi::ft_sfnt_os2) as ffi::TT_OS2_Internal;
            if !os2.is_null() && (*os2).version != 0xffff {
                Some(TrueTypeOS2Table {
                    raw: os2
                })
            } else {
                None
            }
        }
    }

    #[inline(always)]
    pub fn version(&self) -> ffi::FT_UShort {
        unsafe {
            (*self.raw).version
        }
    }

    #[inline(always)]
    pub fn avg_char_width(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).xAvgCharWidth
        }
    }

    #[inline(always)]
    pub fn us_weight_class(&self) -> ffi::FT_UShort {
        unsafe {
            (*self.raw).usWeightClass
        }
    }

    #[inline(always)]
    pub fn us_width_class(&self) -> ffi::FT_UShort {
        unsafe {
            (*self.raw).usWidthClass
        }
    }

    #[inline(always)]
    pub fn fs_type(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).fsType
        }
    }

    #[inline(always)]
    pub fn y_subscript_x_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySubscriptXSize
        }
    }

    #[inline(always)]
    pub fn y_subscript_y_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySubscriptYSize
        }
    }

    #[inline(always)]
    pub fn y_subscript_x_offset(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySubscriptXOffset
        }
    }

    #[inline(always)]
    pub fn y_subscript_y_offset(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySubscriptYOffset
        }
    }

    #[inline(always)]
    pub fn y_superscript_x_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySuperscriptXSize
        }
    }

    #[inline(always)]
    pub fn y_superscript_y_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySuperscriptYSize
        }
    }

    #[inline(always)]
    pub fn y_superscript_x_offset(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySuperscriptXOffset
        }
    }

    #[inline(always)]
    pub fn y_superscript_y_offset(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ySuperscriptYOffset
        }
    }

    #[inline(always)]
    pub fn y_strikeout_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).yStrikeoutSize
        }
    }

    #[inline(always)]
    pub fn y_strikeout_position(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).yStrikeoutPosition
        }
    }

    #[inline(always)]
    pub fn s_family_class(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).sFamilyClass
        }
    }

    #[inline(always)]
    pub fn x_height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).sxHeight
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use model::{ColorMap, FieldCoord, Model, Move, Player};

use self::Event::*;

#[derive(PartialEq)]
pub enum Event {
    Click(FieldCoord),
    Exchange,
    NewGame(ColorMap<Player>),
    Resign,
    Undo,
    Redo,
    Quit,
}

pub fn update(model: &mut Model, event: Option<Event>) -> bool {
    if event == Some(Quit) {
        return false;
    }

    match model.current_player() {
        Player::Human => {
            if let Some(event) = event {
                handle_event(model, &event);
            }
        }
        Player::Computer => {
            if let Some(event) = event {
                match event {
                    Click(_) | Exchange => {}
                    _ => {
                        model.ai.stop();
                        handle_event(model, &event);
                        return true;
                    }
                }
            }

            if !model.is_game_over() {
                if model.ai.is_idle() {
                    let board_list = model.board_list();
                    model.ai.think(model.board, board_list, 6);
                }
                if let Some(mv) = model.ai.try_recv() {
                    model.push_undo_state();
                    model.board.apply_move(&mv);
                    model.last_move = Some(mv);
                    model.update_outcome();
                }
            }
        }
    }
    true
}

fn handle_event(model: &mut Model, event: &Event) {
    match event {
        Click(clicked) => if !model.is_game_over() {
            handle_click(model, *clicked);
        },
        Exchange => if model.board.can_exchange() && !model.is_game_over() {
            model.exchanging = !model.exchanging;
            model.clear_selection();
        },
        NewGame(players) => *model = Model::new(*players),
        Resign => {
            model.push_undo_state();
            model.resign();
        }
        Undo => model.undo_move(),
        Redo => model.redo_move(),
        Quit => unreachable!(),
    }
}

fn handle_click(model: &mut Model, clicked: FieldCoord) {
    match model.selected_piece {
        Some(selected) => {
            if clicked.color() != model.board.turn || selected == clicked {
                model.clear_selection();
            } else if model.board.is_piece_on_field(&clicked) {
                model.selected_piece = Some(clicked);
            } else {
                try_move(model, Move::move_from_field(&selected, &clicked));
                model.clear_selection();
            }
        }
        None => {
            if model.exchanging && try_move(model, Move::exchange_from_field(&clicked)) {
                model.exchanging = false;
            } else if !model.exchanging
                && clicked.color() == model.board.turn
                && model.board.is_piece_on_field(&clicked)
            {
                model.selected_piece = Some(clicked);
            }
        }
    }
}

fn try_move(model: &mut Model, mv: Move) -> bool {
    if model.board.can_apply_move(&mv) {
        model.push_undo_state();
        model.board.apply_move(&mv);
        model.last_move = Some(mv);
        model.update_outcome();
        true
    } else {
        false
    }
}
<commit_msg>Use try_move on AI move<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use model::{ColorMap, FieldCoord, Model, Move, Player};

use self::Event::*;

#[derive(PartialEq)]
pub enum Event {
    Click(FieldCoord),
    Exchange,
    NewGame(ColorMap<Player>),
    Resign,
    Undo,
    Redo,
    Quit,
}

pub fn update(model: &mut Model, event: Option<Event>) -> bool {
    if event == Some(Quit) {
        return false;
    }

    match model.current_player() {
        Player::Human => {
            if let Some(event) = event {
                handle_event(model, &event);
            }
        }
        Player::Computer => {
            if let Some(event) = event {
                match event {
                    Click(_) | Exchange => {}
                    _ => {
                        model.ai.stop();
                        handle_event(model, &event);
                        return true;
                    }
                }
            }

            if !model.is_game_over() {
                if model.ai.is_idle() {
                    let board_list = model.board_list();
                    model.ai.think(model.board, board_list, 6);
                }
                if let Some(mv) = model.ai.try_recv() {
                    try_move(model, mv);
                }
            }
        }
    }
    true
}

fn handle_event(model: &mut Model, event: &Event) {
    match event {
        Click(clicked) => if !model.is_game_over() {
            handle_click(model, *clicked);
        },
        Exchange => if model.board.can_exchange() && !model.is_game_over() {
            model.exchanging = !model.exchanging;
            model.clear_selection();
        },
        NewGame(players) => *model = Model::new(*players),
        Resign => {
            model.push_undo_state();
            model.resign();
        }
        Undo => model.undo_move(),
        Redo => model.redo_move(),
        Quit => unreachable!(),
    }
}

fn handle_click(model: &mut Model, clicked: FieldCoord) {
    match model.selected_piece {
        Some(selected) => {
            if clicked.color() != model.board.turn || selected == clicked {
                model.clear_selection();
            } else if model.board.is_piece_on_field(&clicked) {
                model.selected_piece = Some(clicked);
            } else {
                try_move(model, Move::move_from_field(&selected, &clicked));
                model.clear_selection();
            }
        }
        None => {
            if model.exchanging && try_move(model, Move::exchange_from_field(&clicked)) {
                model.exchanging = false;
            } else if !model.exchanging
                && clicked.color() == model.board.turn
                && model.board.is_piece_on_field(&clicked)
            {
                model.selected_piece = Some(clicked);
            }
        }
    }
}

fn try_move(model: &mut Model, mv: Move) -> bool {
    if model.board.can_apply_move(&mv) {
        model.push_undo_state();
        model.board.apply_move(&mv);
        model.last_move = Some(mv);
        model.update_outcome();
        true
    } else {
        false
    }
}
<|endoftext|>


<commit_before>use inflector::Inflector;

use crate::botocore::{Member, Operation, Shape, ShapeType};
use crate::Service;

// Rest Response Parser
//
// Used by rest-json and rest-xml protocol codegen to generate
// code to parse headers from the http response.
pub fn generate_response_headers_parser(
    service: &Service<'_>,
    operation: &Operation,
) -> Option<String> {
    // nothing to do if there's no output type
    operation.output.as_ref()?;

    let shape = service
        .get_shape(&operation.output.as_ref().unwrap().shape)
        .unwrap();
    let members = shape.members.as_ref().unwrap();

    let parser_pieces = members
        .iter()
        .filter_map(
            |(member_name, member)| match member.location.as_ref().map(String::as_ref) {
                Some("header") => Some(parse_single_header(service, shape, member_name, member)),
                Some("headers") => {
                    Some(parse_multiple_headers(service, shape, member_name, member))
                }
                _ => None,
            },
        )
        .collect::<Vec<String>>();

    if !parser_pieces.is_empty() {
        Some(parser_pieces.join("\n"))
    } else {
        None
    }
}

fn parse_multiple_headers(
    service: &Service<'_>,
    shape: &Shape,
    member_name: &str,
    member: &Member,
) -> String {
    let member_shape = service.get_shape(&member.shape).unwrap();
    let required = shape.required(member_name);
    match member_shape.shape_type {
        ShapeType::Map => parse_headers_map(member_name, member, required),
        ShapeType::List => parse_headers_list(member_name, member, required),
        shape_type => panic!(
            "Unknown header shape type {:?} for {}",
            shape_type, member_name
        ),
    }
}

fn parse_headers_list(member_name: &str, member: &Member, required: bool) -> String {
    let set_statement = if required {
        format!("result.{} = values;", member_name.to_snake_case())
    } else {
        format!("result.{} = Some(values);", member_name.to_snake_case())
    };

    format!(
        "let mut values = Vec::new();
            for (key, value) in response.headers.iter() {{
              if key == \"{location_name}\" {{
                values.push(value);
              }}
            }}
            {set_statement}",
        location_name = member.location_name.as_ref().unwrap(),
        set_statement = set_statement
    )
}

fn parse_headers_map(member_name: &str, member: &Member, required: bool) -> String {
    let set_statement = if required {
        format!("result.{} = values;", member_name.to_snake_case())
    } else {
        format!("result.{} = Some(values);", member_name.to_snake_case())
    };

    format!(
        "let mut values = ::std::collections::HashMap::new();
    for (key, value) in response.headers.iter() {{
        if key.as_str().starts_with(\"{location_name}\") {{
            values.insert(key.as_str()[\"{location_name}\".len()..].to_owned(), value.to_owned());
        }}
    }}
    {set_statement}",
        location_name = member.location_name.as_ref().unwrap(),
        set_statement = set_statement
    )
}

fn parse_single_header(
    service: &Service<'_>,
    shape: &Shape,
    member_name: &str,
    member: &Member,
) -> String {
    let member_shape = service.get_shape(&member.shape).unwrap();
    if shape.required(member_name) {
        format!(
            "let value = response.headers.get(\"{location_name}\").unwrap().to_owned();
                 result.{field_name} = {primitive_parser};",
            location_name = member.location_name.as_ref().unwrap(),
            field_name = member_name.to_snake_case(),
            primitive_parser = generate_header_primitive_parser(member_shape)
        )
    } else {
        format!(
            "if let Some({field_name}) = response.headers.get(\"{location_name}\") {{
                    let value = {field_name}.to_owned();
                    result.{field_name} = Some({primitive_parser})
                  }};",
            location_name = member.location_name.as_ref().unwrap(),
            field_name = member_name.to_snake_case(),
            primitive_parser = generate_header_primitive_parser(member_shape)
        )
    }
}

fn generate_header_primitive_parser(shape: &Shape) -> String {
    let statement = match shape.shape_type {
        ShapeType::String | ShapeType::Timestamp => "value",
        ShapeType::Double => "value.parse::<f64>().unwrap()",
        ShapeType::Integer | ShapeType::Long => "value.parse::<i64>().unwrap()",
        ShapeType::Float => "value.parse::<f32>().unwrap()",
        ShapeType::Boolean => "value.parse::<bool>().unwrap()",
        _ => panic!("Unknown primitive shape type"),
    };

    statement.to_string()
}
<commit_msg>refactor: Simplify header extraction<commit_after>use inflector::Inflector;

use crate::botocore::{Member, Operation, Shape, ShapeType};
use crate::Service;

// Rest Response Parser
//
// Used by rest-json and rest-xml protocol codegen to generate
// code to parse headers from the http response.
pub fn generate_response_headers_parser(
    service: &Service<'_>,
    operation: &Operation,
) -> Option<String> {
    // nothing to do if there's no output type
    operation.output.as_ref()?;

    let shape = service
        .get_shape(&operation.output.as_ref().unwrap().shape)
        .unwrap();
    let members = shape.members.as_ref().unwrap();

    let parser_pieces = members
        .iter()
        .filter_map(
            |(member_name, member)| match member.location.as_ref().map(String::as_ref) {
                Some("header") => Some(parse_single_header(service, shape, member_name, member)),
                Some("headers") => {
                    Some(parse_multiple_headers(service, shape, member_name, member))
                }
                _ => None,
            },
        )
        .collect::<Vec<String>>();

    if !parser_pieces.is_empty() {
        Some(parser_pieces.join("\n"))
    } else {
        None
    }
}

fn parse_multiple_headers(
    service: &Service<'_>,
    shape: &Shape,
    member_name: &str,
    member: &Member,
) -> String {
    let member_shape = service.get_shape(&member.shape).unwrap();
    let required = shape.required(member_name);
    match member_shape.shape_type {
        ShapeType::Map => parse_headers_map(member_name, member, required),
        ShapeType::List => parse_headers_list(member_name, member, required),
        shape_type => panic!(
            "Unknown header shape type {:?} for {}",
            shape_type, member_name
        ),
    }
}

fn parse_headers_list(member_name: &str, member: &Member, required: bool) -> String {
    let set_statement = if required {
        format!("result.{} = values;", member_name.to_snake_case())
    } else {
        format!("result.{} = Some(values);", member_name.to_snake_case())
    };

    format!(
        "let mut values = Vec::new();
            for (key, value) in response.headers.iter() {{
              if key == \"{location_name}\" {{
                values.push(value);
              }}
            }}
            {set_statement}",
        location_name = member.location_name.as_ref().unwrap(),
        set_statement = set_statement
    )
}

fn parse_headers_map(member_name: &str, member: &Member, required: bool) -> String {
    let set_statement = if required {
        format!("result.{} = values;", member_name.to_snake_case())
    } else {
        format!("result.{} = Some(values);", member_name.to_snake_case())
    };

    format!(
        "let mut values = ::std::collections::HashMap::new();
    for (key, value) in response.headers.iter() {{
        if key.as_str().starts_with(\"{location_name}\") {{
            values.insert(key.as_str()[\"{location_name}\".len()..].to_owned(), value.to_owned());
        }}
    }}
    {set_statement}",
        location_name = member.location_name.as_ref().unwrap(),
        set_statement = set_statement
    )
}

fn parse_single_header(
    service: &Service<'_>,
    shape: &Shape,
    member_name: &str,
    member: &Member,
) -> String {
    let member_shape = service.get_shape(&member.shape).unwrap();
    if shape.required(member_name) {
        format!(
            "let value = response.headers.get(\"{location_name}\").unwrap().to_owned();
                 result.{field_name} = {primitive_parser};",
            location_name = member.location_name.as_ref().unwrap(),
            field_name = member_name.to_snake_case(),
            primitive_parser = generate_header_primitive_parser(member_shape)
        )
    } else {
        format!(
            "if let Some(value) = response.headers.get(\"{location_name}\") {{
                    result.{field_name} = Some({primitive_parser})
                  }};",
            location_name = member.location_name.as_ref().unwrap(),
            field_name = member_name.to_snake_case(),
            primitive_parser = generate_header_primitive_parser(member_shape)
        )
    }
}

fn generate_header_primitive_parser(shape: &Shape) -> String {
    let statement = match shape.shape_type {
        ShapeType::String | ShapeType::Timestamp => "value.to_owned()",
        ShapeType::Double => "value.parse::<f64>().unwrap()",
        ShapeType::Integer | ShapeType::Long => "value.parse::<i64>().unwrap()",
        ShapeType::Float => "value.parse::<f32>().unwrap()",
        ShapeType::Boolean => "value.parse::<bool>().unwrap()",
        _ => panic!("Unknown primitive shape type"),
    };

    statement.to_string()
}
<|endoftext|>


<commit_before>mod daily_db_maintenance;
pub mod dump_db;
mod update_downloads;

pub use daily_db_maintenance::daily_db_maintenance;
pub use dump_db::dump_db;
pub use update_downloads::update_downloads;
<commit_msg>worker: Add module doc comment<commit_after>//! The `worker` module contains all the tasks that can be queued up for the
//! background worker process to work on. This includes recurring tasks like
//! the daily database maintenance, but also operations like rendering READMEs
//! and uploading them to S3.

mod daily_db_maintenance;
pub mod dump_db;
mod update_downloads;

pub use daily_db_maintenance::daily_db_maintenance;
pub use dump_db::dump_db;
pub use update_downloads::update_downloads;
<|endoftext|>


<commit_before>//! Utility functions to write nifti images.

use std::fs::File;
use std::io::{BufWriter, Write};
use std::ops::{Div, Sub};
use std::path::{Path, PathBuf};

use byteordered::{ByteOrdered, Endian};
use flate2::write::GzEncoder;
use flate2::Compression;
use ndarray::{ArrayBase, ArrayView, Axis, Data, Dimension, RemoveAxis, ScalarOperand};
use num_traits::FromPrimitive;
use safe_transmute::{guarded_transmute_to_bytes_pod_many, PodTransmutable};

use {
    header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1},
    util::{is_gz_file, is_hdr_file, adapt_bytes},
    volume::element::DataElement,
    NiftiHeader, NiftiType, Result,
};

/// Write a nifti file (.nii or .nii.gz) in Little Endian.
///
/// If a `reference` is given, it will be used to fill most of the header's fields. The voxels
/// intensity will be subtracted by `scl_slope` and divided by `scl_inter`. If `reference` is not
/// given, a default `NiftiHeader` will be built and written.
///
/// In all cases, the `dim`, `datatype` and `bitpix` fields will depend only on `data`, not on the
/// header. In other words, the `datatype` defined in `reference` will be ignored.
pub fn write_nifti<P, A, S, D>(
    header_path: P,
    data: &ArrayBase<S, D>,
    reference: Option<&NiftiHeader>,
) -> Result<()>
where
    P: AsRef<Path>,
    S: Data<Elem = A>,
    A: Copy,
    A: DataElement,
    A: Div<Output = A>,
    A: FromPrimitive,
    A: PodTransmutable,
    A: ScalarOperand,
    A: Sub<Output = A>,
    D: Dimension + RemoveAxis,
{
    let compression_level = Compression::fast();
    let is_gz = is_gz_file(&header_path);
    let (header, data_path) =
        prepare_header_and_paths(&header_path, data, reference, A::DATA_TYPE)?;

    // Need the transpose for fortran ordering used in nifti file format.
    let data = data.t();

    let header_file = File::create(header_path)?;
    if header.vox_offset > 0.0 {
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            write_data(writer.as_mut(), &header, data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(writer.as_mut(), &header)?;
            write_data(writer, &header, data)?;
        }
    } else {
        let data_file = File::create(&data_path)?;
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            let _ = writer.into_inner().finish()?;

            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(data_file, compression_level),
                header.endianness,
            );
            write_data(writer.as_mut(), &header, data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let header_writer =
                ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(header_writer, &header)?;
            let data_writer =
                ByteOrdered::runtime(BufWriter::new(data_file), header.endianness);
            write_data(data_writer, &header, data)?;
        }
    }

    Ok(())
}

/// Write a RGB nifti file (.nii or .nii.gz) in Little Endian.
///
/// If a `reference` is given, it will be used to fill most of the header's fields, except those
/// necessary to be recognized as a RGB image. `scl_slope` will be set to 1.0 and `scl_inter` to
/// 0.0.  If `reference` is not given, a default `NiftiHeader` will be built and written.
pub fn write_rgb_nifti<P, S, D>(
    header_path: P,
    data: &ArrayBase<S, D>,
    reference: Option<&NiftiHeader>,
) -> Result<()>
where
    P: AsRef<Path>,
    S: Data<Elem = [u8; 3]>,
    D: Dimension + RemoveAxis,
{
    let compression_level = Compression::fast();
    let is_gz = is_gz_file(&header_path);
    let (mut header, data_path) =
        prepare_header_and_paths(&header_path, data, reference, NiftiType::Rgb24)?;

    // The `scl_slope` and `scl_inter` fields are ignored on the Rgb24 type.
    header.scl_slope = 1.0;
    header.scl_inter = 0.0;

    // Need the transpose for fortran used in nifti file format.
    let data = data.t();

    let header_file = File::create(header_path)?;
    if header.vox_offset > 0.0 {
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            write_slices::<_, u8, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(writer.as_mut(), &header)?;
            write_slices::<_, u8, _, _, _, _>(writer, data)?;
        }
    } else {
        let data_file = File::create(&data_path)?;
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            let _ = writer.into_inner().finish()?;

            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(data_file, compression_level),
                header.endianness,
            );
            write_slices::<_, u8, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let header_writer =
                ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(header_writer, &header)?;

            let data_writer =
                ByteOrdered::runtime(BufWriter::new(data_file), header.endianness);
            write_slices::<_, u8, _, _, _, _>(data_writer, data)?;
        }
    }

    Ok(())
}

fn prepare_header_and_paths<P, T, D>(
    header_path: P,
    data: &ArrayBase<T, D>,
    reference: Option<&NiftiHeader>,
    datatype: NiftiType,
) -> Result<(NiftiHeader, PathBuf)>
where
    P: AsRef<Path>,
    T: Data,
    D: Dimension,
{
    let mut dim = [1; 8];
    dim[0] = data.ndim() as u16;
    for (i, s) in data.shape().iter().enumerate() {
        dim[i + 1] = *s as u16;
    }

    // If no reference header is given, use the default.
    let reference = match reference {
        Some(r) => r.clone(),
        None => {
            let mut header = NiftiHeader::default();
            header.pixdim = [1.0; 8];
            header.sform_code = 2;
            header.srow_x = [1.0, 0.0, 0.0, 0.0];
            header.srow_y = [0.0, 1.0, 0.0, 0.0];
            header.srow_z = [0.0, 0.0, 1.0, 0.0];
            header
        }
    };

    let mut header = NiftiHeader {
        dim,
        sizeof_hdr: 348,
        datatype: datatype as i16,
        bitpix: (datatype.size_of() * 8) as i16,
        vox_offset: 352.0,
        magic: *MAGIC_CODE_NIP1,
        // All other fields are copied from reference header
        ..reference
    };

    // The only acceptable length is 80. If different, try to set it.
    header.validate_description()?;

    let mut path_buf = PathBuf::from(header_path.as_ref());
    let data_path = if is_hdr_file(&header_path) {
        header.vox_offset = 0.0;
        header.magic = *MAGIC_CODE_NI1;
        let data_path = if is_gz_file(&header_path) {
            let _ = path_buf.set_extension("");
            path_buf.with_extension("img.gz")
        } else {
            path_buf.with_extension("img")
        };
        data_path
    } else {
        path_buf
    };

    Ok((header, data_path))
}

fn write_header<W, E>(mut writer: ByteOrdered<W, E>, header: &NiftiHeader) -> Result<()>
where
    W: Write,
    E: Endian,
{
    writer.write_i32(header.sizeof_hdr)?;
    writer.write_all(&header.data_type)?;
    writer.write_all(&header.db_name)?;
    writer.write_i32(header.extents)?;
    writer.write_i16(header.session_error)?;
    writer.write_u8(header.regular)?;
    writer.write_u8(header.dim_info)?;
    for s in &header.dim {
        writer.write_u16(*s)?;
    }
    writer.write_f32(header.intent_p1)?;
    writer.write_f32(header.intent_p2)?;
    writer.write_f32(header.intent_p3)?;
    writer.write_i16(header.intent_code)?;
    writer.write_i16(header.datatype)?;
    writer.write_i16(header.bitpix)?;
    writer.write_i16(header.slice_start)?;
    for f in &header.pixdim {
        writer.write_f32(*f)?;
    }
    writer.write_f32(header.vox_offset)?;
    writer.write_f32(header.scl_slope)?;
    writer.write_f32(header.scl_inter)?;
    writer.write_i16(header.slice_end)?;
    writer.write_u8(header.slice_code)?;
    writer.write_u8(header.xyzt_units)?;
    writer.write_f32(header.cal_max)?;
    writer.write_f32(header.cal_min)?;
    writer.write_f32(header.slice_duration)?;
    writer.write_f32(header.toffset)?;
    writer.write_i32(header.glmax)?;
    writer.write_i32(header.glmin)?;

    writer.write_all(&header.descrip)?;
    writer.write_all(&header.aux_file)?;
    writer.write_i16(header.qform_code)?;
    writer.write_i16(header.sform_code)?;
    for f in &[
        header.quatern_b,
        header.quatern_c,
        header.quatern_d,
        header.quatern_x,
        header.quatern_y,
        header.quatern_z,
    ] {
        writer.write_f32(*f)?;
    }
    for f in header
        .srow_x
        .iter()
        .chain(&header.srow_y)
        .chain(&header.srow_z)
    {
        writer.write_f32(*f)?;
    }
    writer.write_all(&header.intent_name)?;
    writer.write_all(&header.magic)?;

    // Empty 4 bytes after the header
    // TODO Support writing extension data.
    writer.write_u32(0)?;

    Ok(())
}

/// Write the data in 'f' order.
///
/// Like NiBabel, we iterate by "slice" to improve speed and use less memory.
fn write_data<T, D, W, E>(mut writer: ByteOrdered<W, E>, header: &NiftiHeader, data: ArrayView<T, D>) -> Result<()>
where
    T: Clone + PodTransmutable,
    T: Div<Output = T>,
    T: FromPrimitive,
    T: PodTransmutable,
    T: ScalarOperand,
    T: Sub<Output = T>,
    D: Dimension + RemoveAxis,
    W: Write,
    E: Endian + Copy,
{
    // `1.0x + 0.0` would give the same results, but we avoid a lot of divisions
    let slope = if header.scl_slope == 0.0 {
        1.0
    } else {
        header.scl_slope
    };
    if slope != 1.0 || header.scl_inter != 0.0 {
        // TODO Use linear transformation like when reading. An scl_slope of 0.5 would turn all
        // voxel values to 0 if we pass an ndarray of integers.
        let slope = T::from_f32(slope).unwrap();
        let inter = T::from_f32(header.scl_inter).unwrap();
        for arr_data in data.axis_iter(Axis(0)) {
            write_slice::<T, T, _, _, _, _>(writer.as_mut(), arr_data.sub(inter).div(slope))?;
        }
    } else {
        write_slices::<T, T, _, _, _, _>(writer, data)?;
    }
    Ok(())
}

fn write_slices<A, B, S, D, W, E>(mut writer: ByteOrdered<W, E>, data: ArrayBase<S, D>) -> Result<()>
where
    S: Data<Elem = A>,
    A: Clone + PodTransmutable,
    D: Dimension + RemoveAxis,
    W: Write,
    E: Endian + Copy,
{
    let mut iter = data.axis_iter(Axis(0));
    if let Some(arr_data) = iter.next() {
        // Keep slice voxels in a separate array to ensure `C` ordering even after `into_shape`.
        let mut slice = arr_data.to_owned();
        write_slice::<_, B, _, _, _, _>(writer.as_mut(), slice.view())?;
        for arr_data in iter {
            slice.assign(&arr_data);
            write_slice::<_, B, _, _, _, _>(writer.as_mut(), slice.view())?;
        }
    }
    Ok(())
}

fn write_slice<A, B, S, D, W, E>(writer: ByteOrdered<&mut W, E>, data: ArrayBase<S, D>) -> Result<()>
where
    S: Data<Elem = A>,
    A: Clone + PodTransmutable,
    D: Dimension,
    W: Write,
    E: Endian,
{
    let len = data.len();
    let arr_data = data.into_shape(len).unwrap();
    let slice = arr_data.as_slice().unwrap();
    let bytes = guarded_transmute_to_bytes_pod_many(slice);
    let (writer, endianness) = writer.into_parts();
    let bytes = adapt_bytes::<B, _>(&bytes, endianness);
    writer.write_all(&*bytes)?;
    Ok(())
}
<commit_msg>Force signal=1.0 amd inter=0.0<commit_after>//! Utility functions to write nifti images.

use std::fs::File;
use std::io::{BufWriter, Write};
use std::ops::{Div, Sub};
use std::path::{Path, PathBuf};

use byteordered::{ByteOrdered, Endian};
use flate2::write::GzEncoder;
use flate2::Compression;
use ndarray::{ArrayBase, ArrayView, Axis, Data, Dimension, RemoveAxis, ScalarOperand};
use num_traits::FromPrimitive;
use safe_transmute::{guarded_transmute_to_bytes_pod_many, PodTransmutable};

use {
    header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1},
    util::{is_gz_file, is_hdr_file, adapt_bytes},
    volume::element::DataElement,
    NiftiHeader, NiftiType, Result,
};

/// Write a nifti file (.nii or .nii.gz).
///
/// If a `reference` is given, it will be used to fill most of the header's fields. Otherwise, a
/// default `NiftiHeader` will be built and written. In all cases, the `dim`, `datatype` and
/// `bitpix` fields will depend only on `data`, not on the header. This means that the `datatype`
/// defined in `reference` will be ignored. Because of this, `scl_slope` will be set to 1.0 and
/// `scl_inter` to 0.0.
pub fn write_nifti<P, A, S, D>(
    header_path: P,
    data: &ArrayBase<S, D>,
    reference: Option<&NiftiHeader>,
) -> Result<()>
where
    P: AsRef<Path>,
    S: Data<Elem = A>,
    A: Copy,
    A: DataElement,
    A: Div<Output = A>,
    A: FromPrimitive,
    A: PodTransmutable,
    A: ScalarOperand,
    A: Sub<Output = A>,
    D: Dimension + RemoveAxis,
{
    let compression_level = Compression::fast();
    let is_gz = is_gz_file(&header_path);
    let (header, data_path) =
        prepare_header_and_paths(&header_path, data, reference, A::DATA_TYPE)?;

    // Need the transpose for fortran ordering used in nifti file format.
    let data = data.t();

    let header_file = File::create(header_path)?;
    if header.vox_offset > 0.0 {
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            write_data(writer.as_mut(), &header, data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(writer.as_mut(), &header)?;
            write_data(writer, &header, data)?;
        }
    } else {
        let data_file = File::create(&data_path)?;
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            let _ = writer.into_inner().finish()?;

            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(data_file, compression_level),
                header.endianness,
            );
            write_data(writer.as_mut(), &header, data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let header_writer =
                ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(header_writer, &header)?;
            let data_writer =
                ByteOrdered::runtime(BufWriter::new(data_file), header.endianness);
            write_data(data_writer, &header, data)?;
        }
    }

    Ok(())
}

/// Write a RGB nifti file (.nii or .nii.gz).
///
/// If a `reference` is given, it will be used to fill most of the header's fields, except those
/// necessary to be recognized as a RGB image. `scl_slope` will be set to 1.0 and `scl_inter` to
/// 0.0. If `reference` is not given, a default `NiftiHeader` will be built and written.
pub fn write_rgb_nifti<P, S, D>(
    header_path: P,
    data: &ArrayBase<S, D>,
    reference: Option<&NiftiHeader>,
) -> Result<()>
where
    P: AsRef<Path>,
    S: Data<Elem = [u8; 3]>,
    D: Dimension + RemoveAxis,
{
    let compression_level = Compression::fast();
    let is_gz = is_gz_file(&header_path);
    let (header, data_path) =
        prepare_header_and_paths(&header_path, data, reference, NiftiType::Rgb24)?;

    // Need the transpose for fortran used in nifti file format.
    let data = data.t();

    let header_file = File::create(header_path)?;
    if header.vox_offset > 0.0 {
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            write_slices::<_, u8, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(writer.as_mut(), &header)?;
            write_slices::<_, u8, _, _, _, _>(writer, data)?;
        }
    } else {
        let data_file = File::create(&data_path)?;
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            let _ = writer.into_inner().finish()?;

            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(data_file, compression_level),
                header.endianness,
            );
            write_slices::<_, u8, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let header_writer =
                ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(header_writer, &header)?;

            let data_writer =
                ByteOrdered::runtime(BufWriter::new(data_file), header.endianness);
            write_slices::<_, u8, _, _, _, _>(data_writer, data)?;
        }
    }

    Ok(())
}

fn prepare_header_and_paths<P, T, D>(
    header_path: P,
    data: &ArrayBase<T, D>,
    reference: Option<&NiftiHeader>,
    datatype: NiftiType,
) -> Result<(NiftiHeader, PathBuf)>
where
    P: AsRef<Path>,
    T: Data,
    D: Dimension,
{
    let mut dim = [1; 8];
    dim[0] = data.ndim() as u16;
    for (i, s) in data.shape().iter().enumerate() {
        dim[i + 1] = *s as u16;
    }

    // If no reference header is given, use the default.
    let reference = match reference {
        Some(r) => r.clone(),
        None => {
            let mut header = NiftiHeader::default();
            header.pixdim = [1.0; 8];
            header.sform_code = 2;
            header.srow_x = [1.0, 0.0, 0.0, 0.0];
            header.srow_y = [0.0, 1.0, 0.0, 0.0];
            header.srow_z = [0.0, 0.0, 1.0, 0.0];
            header
        }
    };

    let mut header = NiftiHeader {
        dim,
        sizeof_hdr: 348,
        datatype: datatype as i16,
        bitpix: (datatype.size_of() * 8) as i16,
        vox_offset: 352.0,
        scl_inter: 0.0,
        scl_slope: 1.0,
        magic: *MAGIC_CODE_NIP1,
        // All other fields are copied from reference header
        ..reference
    };

    // The only acceptable length is 80. If different, try to set it.
    header.validate_description()?;

    let mut path_buf = PathBuf::from(header_path.as_ref());
    let data_path = if is_hdr_file(&header_path) {
        header.vox_offset = 0.0;
        header.magic = *MAGIC_CODE_NI1;
        let data_path = if is_gz_file(&header_path) {
            let _ = path_buf.set_extension("");
            path_buf.with_extension("img.gz")
        } else {
            path_buf.with_extension("img")
        };
        data_path
    } else {
        path_buf
    };

    Ok((header, data_path))
}

fn write_header<W, E>(mut writer: ByteOrdered<W, E>, header: &NiftiHeader) -> Result<()>
where
    W: Write,
    E: Endian,
{
    writer.write_i32(header.sizeof_hdr)?;
    writer.write_all(&header.data_type)?;
    writer.write_all(&header.db_name)?;
    writer.write_i32(header.extents)?;
    writer.write_i16(header.session_error)?;
    writer.write_u8(header.regular)?;
    writer.write_u8(header.dim_info)?;
    for s in &header.dim {
        writer.write_u16(*s)?;
    }
    writer.write_f32(header.intent_p1)?;
    writer.write_f32(header.intent_p2)?;
    writer.write_f32(header.intent_p3)?;
    writer.write_i16(header.intent_code)?;
    writer.write_i16(header.datatype)?;
    writer.write_i16(header.bitpix)?;
    writer.write_i16(header.slice_start)?;
    for f in &header.pixdim {
        writer.write_f32(*f)?;
    }
    writer.write_f32(header.vox_offset)?;
    writer.write_f32(header.scl_slope)?;
    writer.write_f32(header.scl_inter)?;
    writer.write_i16(header.slice_end)?;
    writer.write_u8(header.slice_code)?;
    writer.write_u8(header.xyzt_units)?;
    writer.write_f32(header.cal_max)?;
    writer.write_f32(header.cal_min)?;
    writer.write_f32(header.slice_duration)?;
    writer.write_f32(header.toffset)?;
    writer.write_i32(header.glmax)?;
    writer.write_i32(header.glmin)?;

    writer.write_all(&header.descrip)?;
    writer.write_all(&header.aux_file)?;
    writer.write_i16(header.qform_code)?;
    writer.write_i16(header.sform_code)?;
    for f in &[
        header.quatern_b,
        header.quatern_c,
        header.quatern_d,
        header.quatern_x,
        header.quatern_y,
        header.quatern_z,
    ] {
        writer.write_f32(*f)?;
    }
    for f in header
        .srow_x
        .iter()
        .chain(&header.srow_y)
        .chain(&header.srow_z)
    {
        writer.write_f32(*f)?;
    }
    writer.write_all(&header.intent_name)?;
    writer.write_all(&header.magic)?;

    // Empty 4 bytes after the header
    // TODO Support writing extension data.
    writer.write_u32(0)?;

    Ok(())
}

/// Write the data in 'f' order.
///
/// Like NiBabel, we iterate by "slice" to improve speed and use less memory.
fn write_data<T, D, W, E>(mut writer: ByteOrdered<W, E>, header: &NiftiHeader, data: ArrayView<T, D>) -> Result<()>
where
    T: Clone + PodTransmutable,
    T: Div<Output = T>,
    T: FromPrimitive,
    T: PodTransmutable,
    T: ScalarOperand,
    T: Sub<Output = T>,
    D: Dimension + RemoveAxis,
    W: Write,
    E: Endian + Copy,
{
    // `1.0x + 0.0` would give the same results, but we avoid a lot of divisions
    let slope = if header.scl_slope == 0.0 {
        1.0
    } else {
        header.scl_slope
    };
    if slope != 1.0 || header.scl_inter != 0.0 {
        // TODO Use linear transformation like when reading. An scl_slope of 0.5 would turn all
        // voxel values to 0 if we pass an ndarray of integers.
        let slope = T::from_f32(slope).unwrap();
        let inter = T::from_f32(header.scl_inter).unwrap();
        for arr_data in data.axis_iter(Axis(0)) {
            write_slice::<T, T, _, _, _, _>(writer.as_mut(), arr_data.sub(inter).div(slope))?;
        }
    } else {
        write_slices::<T, T, _, _, _, _>(writer, data)?;
    }
    Ok(())
}

fn write_slices<A, B, S, D, W, E>(mut writer: ByteOrdered<W, E>, data: ArrayBase<S, D>) -> Result<()>
where
    S: Data<Elem = A>,
    A: Clone + PodTransmutable,
    D: Dimension + RemoveAxis,
    W: Write,
    E: Endian + Copy,
{
    let mut iter = data.axis_iter(Axis(0));
    if let Some(arr_data) = iter.next() {
        // Keep slice voxels in a separate array to ensure `C` ordering even after `into_shape`.
        let mut slice = arr_data.to_owned();
        write_slice::<_, B, _, _, _, _>(writer.as_mut(), slice.view())?;
        for arr_data in iter {
            slice.assign(&arr_data);
            write_slice::<_, B, _, _, _, _>(writer.as_mut(), slice.view())?;
        }
    }
    Ok(())
}

fn write_slice<A, B, S, D, W, E>(writer: ByteOrdered<&mut W, E>, data: ArrayBase<S, D>) -> Result<()>
where
    S: Data<Elem = A>,
    A: Clone + PodTransmutable,
    D: Dimension,
    W: Write,
    E: Endian,
{
    let len = data.len();
    let arr_data = data.into_shape(len).unwrap();
    let slice = arr_data.as_slice().unwrap();
    let bytes = guarded_transmute_to_bytes_pod_many(slice);
    let (writer, endianness) = writer.into_parts();
    let bytes = adapt_bytes::<B, _>(&bytes, endianness);
    writer.write_all(&*bytes)?;
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Unix-specific extensions to primitives in the `std::process` module.

#![stable(feature = "rust1", since = "1.0.0")]

use io;
use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
use process;
use sys;
use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};

/// Unix-specific extensions to the `std::process::Command` builder
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
    /// Sets the child process's user id. This translates to a
    /// `setuid` call in the child process. Failure in the `setuid`
    /// call will cause the spawn to fail.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn uid(&mut self, id: u32) -> &mut process::Command;

    /// Similar to `uid`, but sets the group id of the child process. This has
    /// the same semantics as the `uid` field.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn gid(&mut self, id: u32) -> &mut process::Command;

    /// Schedules a closure to be run just before the `exec` function is
    /// invoked.
    ///
    /// The closure is allowed to return an I/O error whose OS error code will
    /// be communicated back to the parent and returned as an error from when
    /// the spawn was requested.
    ///
    /// Multiple closures can be registered and they will be called in order of
    /// their registration. If a closure returns `Err` then no further closures
    /// will be called and the spawn operation will immediately return with a
    /// failure.
    ///
    /// # Notes
    ///
    /// This closure will be run in the context of the child process after a
    /// `fork`. This primarily means that any modificatons made to memory on
    /// behalf of this closure will **not** be visible to the parent process.
    /// This is often a very constrained environment where normal operations
    /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
    /// other threads perhaps still running when the `fork` was run).
    ///
    /// When this closure is run, aspects such as the stdio file descriptors and
    /// working directory have successfully been changed, so output to these
    /// locations may not appear where intended.
    #[unstable(feature = "process_exec", issue = "31398")]
    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
        where F: FnMut() -> io::Result<()> + Send + Sync + 'static;

    /// Performs all the required setup by this `Command`, followed by calling
    /// the `execvp` syscall.
    ///
    /// On success this function will not return, and otherwise it will return
    /// an error indicating why the exec (or another part of the setup of the
    /// `Command`) failed.
    ///
    /// This function, unlike `spawn`, will **not** `fork` the process to create
    /// a new child. Like spawn, however, the default behavior for the stdio
    /// descriptors will be to inherited from the current process.
    ///
    /// # Notes
    ///
    /// The process may be in a "broken state" if this function returns in
    /// error. For example the working directory, environment variables, signal
    /// handling settings, various user/group information, or aspects of stdio
    /// file descriptors may have changed. If a "transactional spawn" is
    /// required to gracefully handle errors it is recommended to use the
    /// cross-platform `spawn` instead.
    #[stable(feature = "process_exec2", since = "1.9.0")]
    fn exec(&mut self) -> io::Error;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl CommandExt for process::Command {
    fn uid(&mut self, id: u32) -> &mut process::Command {
        self.as_inner_mut().uid(id);
        self
    }

    fn gid(&mut self, id: u32) -> &mut process::Command {
        self.as_inner_mut().gid(id);
        self
    }

    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
        where F: FnMut() -> io::Result<()> + Send + Sync + 'static
    {
        self.as_inner_mut().before_exec(Box::new(f));
        self
    }

    fn exec(&mut self) -> io::Error {
        self.as_inner_mut().exec(sys::process::Stdio::Inherit)
    }
}

/// Unix-specific extensions to `std::process::ExitStatus`
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
    /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
    /// a process.
    #[stable(feature = "exit_status_from", since = "1.12.0")]
    fn from_raw(raw: i32) -> Self;

    /// If the process was terminated by a signal, returns that signal.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn signal(&self) -> Option<i32>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl ExitStatusExt for process::ExitStatus {
    fn from_raw(raw: i32) -> Self {
        process::ExitStatus::from_inner(From::from(raw))
    }

    fn signal(&self) -> Option<i32> {
        self.as_inner().signal()
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl FromRawFd for process::Stdio {
    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
        let fd = sys::fd::FileDesc::new(fd);
        let io = sys::process::Stdio::Fd(fd);
        process::Stdio::from_inner(io)
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdin {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().raw()
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdout {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().raw()
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStderr {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().raw()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdin {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdout {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStderr {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}
<commit_msg>Stabilize std::os::unix::process::CommandExt::before_exec<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Unix-specific extensions to primitives in the `std::process` module.

#![stable(feature = "rust1", since = "1.0.0")]

use io;
use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
use process;
use sys;
use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};

/// Unix-specific extensions to the `std::process::Command` builder
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
    /// Sets the child process's user id. This translates to a
    /// `setuid` call in the child process. Failure in the `setuid`
    /// call will cause the spawn to fail.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn uid(&mut self, id: u32) -> &mut process::Command;

    /// Similar to `uid`, but sets the group id of the child process. This has
    /// the same semantics as the `uid` field.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn gid(&mut self, id: u32) -> &mut process::Command;

    /// Schedules a closure to be run just before the `exec` function is
    /// invoked.
    ///
    /// The closure is allowed to return an I/O error whose OS error code will
    /// be communicated back to the parent and returned as an error from when
    /// the spawn was requested.
    ///
    /// Multiple closures can be registered and they will be called in order of
    /// their registration. If a closure returns `Err` then no further closures
    /// will be called and the spawn operation will immediately return with a
    /// failure.
    ///
    /// # Notes
    ///
    /// This closure will be run in the context of the child process after a
    /// `fork`. This primarily means that any modificatons made to memory on
    /// behalf of this closure will **not** be visible to the parent process.
    /// This is often a very constrained environment where normal operations
    /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
    /// other threads perhaps still running when the `fork` was run).
    ///
    /// When this closure is run, aspects such as the stdio file descriptors and
    /// working directory have successfully been changed, so output to these
    /// locations may not appear where intended.
    #[stable(feature = "process_exec", since = "1.15.0")]
    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
        where F: FnMut() -> io::Result<()> + Send + Sync + 'static;

    /// Performs all the required setup by this `Command`, followed by calling
    /// the `execvp` syscall.
    ///
    /// On success this function will not return, and otherwise it will return
    /// an error indicating why the exec (or another part of the setup of the
    /// `Command`) failed.
    ///
    /// This function, unlike `spawn`, will **not** `fork` the process to create
    /// a new child. Like spawn, however, the default behavior for the stdio
    /// descriptors will be to inherited from the current process.
    ///
    /// # Notes
    ///
    /// The process may be in a "broken state" if this function returns in
    /// error. For example the working directory, environment variables, signal
    /// handling settings, various user/group information, or aspects of stdio
    /// file descriptors may have changed. If a "transactional spawn" is
    /// required to gracefully handle errors it is recommended to use the
    /// cross-platform `spawn` instead.
    #[stable(feature = "process_exec2", since = "1.9.0")]
    fn exec(&mut self) -> io::Error;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl CommandExt for process::Command {
    fn uid(&mut self, id: u32) -> &mut process::Command {
        self.as_inner_mut().uid(id);
        self
    }

    fn gid(&mut self, id: u32) -> &mut process::Command {
        self.as_inner_mut().gid(id);
        self
    }

    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
        where F: FnMut() -> io::Result<()> + Send + Sync + 'static
    {
        self.as_inner_mut().before_exec(Box::new(f));
        self
    }

    fn exec(&mut self) -> io::Error {
        self.as_inner_mut().exec(sys::process::Stdio::Inherit)
    }
}

/// Unix-specific extensions to `std::process::ExitStatus`
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
    /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
    /// a process.
    #[stable(feature = "exit_status_from", since = "1.12.0")]
    fn from_raw(raw: i32) -> Self;

    /// If the process was terminated by a signal, returns that signal.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn signal(&self) -> Option<i32>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl ExitStatusExt for process::ExitStatus {
    fn from_raw(raw: i32) -> Self {
        process::ExitStatus::from_inner(From::from(raw))
    }

    fn signal(&self) -> Option<i32> {
        self.as_inner().signal()
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl FromRawFd for process::Stdio {
    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
        let fd = sys::fd::FileDesc::new(fd);
        let io = sys::process::Stdio::Fd(fd);
        process::Stdio::from_inner(io)
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdin {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().raw()
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdout {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().raw()
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStderr {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().raw()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdin {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdout {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStderr {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}
<|endoftext|>


<commit_before>//! This module includes a high level abstraction over a DICOM data element's value.

use data::{Tag, Length};

use chrono::{DateTime, FixedOffset, NaiveDate, NaiveTime};
use error::CastValueError;
use itertools::Itertools;
use std::borrow::Cow;

type C<T> = Vec<T>;

/// Representation of a full DICOM value, which may be either primitive or
/// another DICOM object.
#[derive(Debug, Clone, PartialEq)]
pub enum Value<I> {
    /// Primitive value
    Primitive(PrimitiveValue),
    /// A complex sequence of items
    Sequence {
        /// Item collection.
        items: C<I>,
        /// The size in bytes.
        size: Length,
    },
}

impl<I> Value<I>
where
    I: DicomValueType,
{
    /// Obtain the number of individual values.
    /// In a sequence item, this is the number of items.
    pub fn multiplicity(&self) -> u32 {
        match *self {
            Value::Primitive(ref v) => v.multiplicity(),
            Value::Sequence{ ref items, ..} => items.len() as u32,
        }
    }

    /// Gets a reference to the primitive value.
    pub fn primitive(&self) -> Option<&PrimitiveValue> {
        match *self {
            Value::Primitive(ref v) => Some(v),
            _ => None,
        }
    }

    /// Gets a reference to the items.
    pub fn item(&self) -> Option<&[I]> {
        match *self {
            Value::Sequence { ref items, .. } => Some(items),
            _ => None,
        }
    }

    /// Retrieves the primitive value.
    pub fn into_primitive(self) -> Option<PrimitiveValue> {
        match self {
            Value::Primitive(v) => Some(v),
            _ => None,
        }
    }

    /// Retrieves the items.
    pub fn into_item(self) -> Option<Vec<I>> {
        match self {
            Value::Sequence { items, .. } => Some(items),
            _ => None,
        }
    }

    pub fn as_string(&self) -> Result<Cow<str>, CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::Str(ref v)) => Ok(Cow::from(v.as_ref())),
            &Value::Primitive(PrimitiveValue::Strs(ref v)) => {
                Ok(Cow::from(v.into_iter().join("\\")))
            }
            _ => Err(CastValueError {
                requested: "string",
                got: self.value_type(),
            }),
        }
    }

    pub fn as_u8(&self) -> Result<&[u8], CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::U8(ref v)) => Ok(&v),
            _ => Err(CastValueError {
                requested: "u8",
                got: self.value_type(),
            }),
        }
    }

    pub fn as_i32(&self) -> Result<&[i32], CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::I32(ref v)) => Ok(&v),
            _ => Err(CastValueError {
                requested: "i32",
                got: self.value_type(),
            }),
        }
    }

    pub fn to_tag(&self) -> Result<Tag, CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::Tags(ref v)) => Ok(v[0]),
            _ => Err(CastValueError {
                requested: "tag",
                got: self.value_type(),
            }),
        }
    }

    pub fn as_tags(&self) -> Result<&[Tag], CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::Tags(ref v)) => Ok(&v),
            _ => Err(CastValueError {
                requested: "tag",
                got: self.value_type(),
            }),
        }
    }
}

impl<I> From<PrimitiveValue> for Value<I> {
    fn from(v: PrimitiveValue) -> Self {
        Value::Primitive(v)
    }
}

/// An enum representing a primitive value from a DICOM element. The result of decoding
/// an element's data value may be one of the enumerated types depending on its content
/// and value representation.
#[derive(Debug, PartialEq, Clone)]
pub enum PrimitiveValue {
    /// No data. Used for SQ (regardless of content) and any value of length 0.
    Empty,

    /// A sequence of strings.
    /// Used for AE, AS, PN, SH, CS, LO, UI and UC.
    /// Can also be used for IS, SS, DS, DA, DT and TM when decoding
    /// with format preservation.
    Strs(C<String>),

    /// A single string.
    /// Used for ST, LT, UT and UR, which are never multi-valued.
    Str(String),

    /// A sequence of attribute tags.
    /// Used specifically for AT.
    Tags(C<Tag>),

    /// The value is a sequence of unsigned 16-bit integers.
    /// Used for OB and UN.
    U8(C<u8>),

    /// The value is a sequence of signed 16-bit integers.
    /// Used for SS.
    I16(C<i16>),

    /// A sequence of unsigned 168-bit integers.
    /// Used for US and OW.
    U16(C<u16>),

    /// A sequence of signed 32-bit integers.
    /// Used for SL and IS.
    I32(C<i32>),

    /// A sequence of unsigned 32-bit integers.
    /// Used for UL and OL.
    U32(C<u32>),

    /// The value is a sequence of 32-bit floating point numbers.
    /// Used for OF and FL.
    F32(C<f32>),

    /// The value is a sequence of 64-bit floating point numbers.
    /// Used for OD and FD, DS.
    F64(C<f64>),

    /// A sequence of dates.
    /// Used for the DA representation.
    Date(C<NaiveDate>),

    /// A sequence of date-time values.
    /// Used for the DT representation.
    DateTime(C<DateTime<FixedOffset>>),

    /// A sequence of time values.
    /// Used for the TM representation.
    Time(C<NaiveTime>),
}

impl PrimitiveValue {

    /// Obtain the number of individual values.
    pub fn multiplicity(&self) -> u32 {
        use self::PrimitiveValue::*;
        match self {
            &Empty => 0,
            &Str(_) => 1,
            &Strs(ref c) => c.len() as u32,
            &Tags(ref c) => c.len() as u32,
            &U8(ref c) => c.len() as u32,
            &I16(ref c) => c.len() as u32,
            &U16(ref c) => c.len() as u32,
            &I32(ref c) => c.len() as u32,
            &U32(ref c) => c.len() as u32,
            &F32(ref c) => c.len() as u32,
            &F64(ref c) => c.len() as u32,
            &Date(ref c) => c.len() as u32,
            &DateTime(ref c) => c.len() as u32,
            &Time(ref c) => c.len() as u32,
        }
    }

    /// Get a single string value. If it contains multiple strings,
    /// only the first one is returned.
    pub fn string(&self) -> Option<&str> {
        use self::PrimitiveValue::*;
        match self {
            &Strs(ref c) => c.get(0).map(String::as_str),
            &Str(ref s) => Some(s),
            _ => None,
        }
    }

    /// Get a sequence of string values.
    pub fn strings(&self) -> Option<Vec<&str>> {
        use self::PrimitiveValue::*;
        match self {
            &Strs(ref c) => Some(c.iter().map(String::as_str).collect()),
            &Str(ref s) => Some(vec![&s]),
            _ => None,
        }
    }

    /// Get a single DICOM tag.
    pub fn tag(&self) -> Option<Tag> {
        use self::PrimitiveValue::*;
        match self {
            &Tags(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a sequence of DICOM tags.
    pub fn tags(&self) -> Option<&[Tag]> {
        use self::PrimitiveValue::*;
        match self {
            &Tags(ref c) => Some(&c),
            _ => None,
        }
    }

    /// Get a single 32-bit signed integer value.
    pub fn int32(&self) -> Option<i32> {
        use self::PrimitiveValue::*;
        match self {
            &I32(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 32-bit unsigned integer value.
    pub fn uint32(&self) -> Option<u32> {
        use self::PrimitiveValue::*;
        match self {
            &U32(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 16-bit signed integer value.
    pub fn int16(&self) -> Option<i16> {
        use self::PrimitiveValue::*;
        match self {
            &I16(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 16-bit unsigned integer value.
    pub fn uint16(&self) -> Option<u16> {
        use self::PrimitiveValue::*;
        match self {
            &U16(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 8-bit unsigned integer value.
    pub fn uint8(&self) -> Option<u8> {
        use self::PrimitiveValue::*;
        match self {
            &U8(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 32-bit floating point number value.
    pub fn float32(&self) -> Option<f32> {
        use self::PrimitiveValue::*;
        match self {
            &F32(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 64-bit floating point number value.
    pub fn float64(&self) -> Option<f64> {
        use self::PrimitiveValue::*;
        match self {
            &F64(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }
}

/// An enum representing an abstraction of a DICOM element's data value type.
/// This should be the equivalent of `PrimitiveValue` without the content,
/// plus the `Item` entry.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ValueType {
    /// No data. Used for any value of length 0.
    Empty,

    /// An item. Used for elements in a SQ, regardless of content.
    Item,

    /// A sequence of strings.
    /// Used for AE, AS, PN, SH, CS, LO, UI and UC.
    /// Can also be used for IS, SS, DS, DA, DT and TM when decoding
    /// with format preservation.
    Strs,

    /// A single string.
    /// Used for ST, LT, UT and UR, which are never multi-valued.
    Str,

    /// A sequence of attribute tags.
    /// Used specifically for AT.
    Tags,

    /// The value is a sequence of unsigned 16-bit integers.
    /// Used for OB and UN.
    U8,

    /// The value is a sequence of signed 16-bit integers.
    /// Used for SS.
    I16,

    /// A sequence of unsigned 168-bit integers.
    /// Used for US and OW.
    U16,

    /// A sequence of signed 32-bit integers.
    /// Used for SL and IS.
    I32,

    /// A sequence of unsigned 32-bit integers.
    /// Used for UL and OL.
    U32,

    /// The value is a sequence of 32-bit floating point numbers.
    /// Used for OF and FL.
    F32,

    /// The value is a sequence of 64-bit floating point numbers.
    /// Used for OD, FD and DS.
    F64,

    /// A sequence of dates.
    /// Used for the DA representation.
    Date,

    /// A sequence of date-time values.
    /// Used for the DT representation.
    DateTime,

    /// A sequence of time values.
    /// Used for the TM representation.
    Time,
}

/// A trait for a value that maps to a DICOM element data value.
pub trait DicomValueType {
    /// Retrieve the specific type of this value.
    fn value_type(&self) -> ValueType;

    /// Retrieve the number of values contained.
    fn size(&self) -> Length;

    /// Check whether the value is empty (0 length).
    fn is_empty(&self) -> bool {
        self.size() == Length(0)
    }
}

impl DicomValueType for PrimitiveValue {
    fn value_type(&self) -> ValueType {
        use self::PrimitiveValue::*;
        match *self {
            Empty => ValueType::Empty,
            Date(_) => ValueType::Date,
            DateTime(_) => ValueType::DateTime,
            F32(_) => ValueType::F32,
            F64(_) => ValueType::F64,
            I16(_) => ValueType::I16,
            I32(_) => ValueType::I32,
            Str(_) => ValueType::Str,
            Strs(_) => ValueType::Strs,
            Tags(_) => ValueType::Tags,
            Time(_) => ValueType::Time,
            U16(_) => ValueType::U16,
            U32(_) => ValueType::U32,
            U8(_) => ValueType::U8,
        }
    }

    fn size(&self) -> Length {
        use self::PrimitiveValue::*;
        Length::defined(match *self {
            Empty => 0,
            Str(_) => 1,
            Date(ref b) => b.len() as u32,
            DateTime(ref b) => b.len() as u32,
            F32(ref b) => b.len() as u32,
            F64(ref b) => b.len() as u32,
            I16(ref b) => b.len() as u32,
            I32(ref b) => b.len() as u32,
            Strs(ref b) => b.len() as u32,
            Tags(ref b) => b.len() as u32,
            Time(ref b) => b.len() as u32,
            U16(ref b) => b.len() as u32,
            U32(ref b) => b.len() as u32,
            U8(ref b) => b.len() as u32,
        })
    }
}

impl<I> DicomValueType for Value<I>
where
    I: DicomValueType,
{
    fn value_type(&self) -> ValueType {
        match *self {
            Value::Primitive(ref v) => v.value_type(),
            Value::Sequence { .. } => ValueType::Item,
        }
    }

    fn size(&self) -> Length {
        match *self {
            Value::Primitive(ref v) => v.size(),
            Value::Sequence { size, .. } => size,
        }
    }
}
<commit_msg>Avoid rust-lang/rust#51844 regression<commit_after>//! This module includes a high level abstraction over a DICOM data element's value.

use data::{Tag, Length};

use chrono::{DateTime, FixedOffset, NaiveDate, NaiveTime};
use error::CastValueError;
use itertools::Itertools;
use std::borrow::Cow;

type C<T> = Vec<T>;

/// Representation of a full DICOM value, which may be either primitive or
/// another DICOM object.
#[derive(Debug, Clone, PartialEq)]
pub enum Value<I> {
    /// Primitive value
    Primitive(PrimitiveValue),
    /// A complex sequence of items
    Sequence {
        /// Item collection.
        items: C<I>,
        /// The size in bytes.
        size: Length,
    },
}

impl<I> Value<I>
where
    I: DicomValueType,
{
    /// Obtain the number of individual values.
    /// In a sequence item, this is the number of items.
    pub fn multiplicity(&self) -> u32 {
        match *self {
            Value::Primitive(ref v) => v.multiplicity(),
            Value::Sequence{ ref items, ..} => items.len() as u32,
        }
    }

    /// Gets a reference to the primitive value.
    pub fn primitive(&self) -> Option<&PrimitiveValue> {
        match *self {
            Value::Primitive(ref v) => Some(v),
            _ => None,
        }
    }

    /// Gets a reference to the items.
    pub fn item(&self) -> Option<&[I]> {
        match *self {
            Value::Sequence { ref items, .. } => Some(items),
            _ => None,
        }
    }

    /// Retrieves the primitive value.
    pub fn into_primitive(self) -> Option<PrimitiveValue> {
        match self {
            Value::Primitive(v) => Some(v),
            _ => None,
        }
    }

    /// Retrieves the items.
    pub fn into_item(self) -> Option<Vec<I>> {
        match self {
            Value::Sequence { items, .. } => Some(items),
            _ => None,
        }
    }

    pub fn as_string(&self) -> Result<Cow<str>, CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::Str(ref v)) => Ok(Cow::from(v.as_str())),
            &Value::Primitive(PrimitiveValue::Strs(ref v)) => {
                Ok(Cow::from(v.into_iter().join("\\")))
            }
            _ => Err(CastValueError {
                requested: "string",
                got: self.value_type(),
            }),
        }
    }

    pub fn as_u8(&self) -> Result<&[u8], CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::U8(ref v)) => Ok(&v),
            _ => Err(CastValueError {
                requested: "u8",
                got: self.value_type(),
            }),
        }
    }

    pub fn as_i32(&self) -> Result<&[i32], CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::I32(ref v)) => Ok(&v),
            _ => Err(CastValueError {
                requested: "i32",
                got: self.value_type(),
            }),
        }
    }

    pub fn to_tag(&self) -> Result<Tag, CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::Tags(ref v)) => Ok(v[0]),
            _ => Err(CastValueError {
                requested: "tag",
                got: self.value_type(),
            }),
        }
    }

    pub fn as_tags(&self) -> Result<&[Tag], CastValueError> {
        match self {
            &Value::Primitive(PrimitiveValue::Tags(ref v)) => Ok(&v),
            _ => Err(CastValueError {
                requested: "tag",
                got: self.value_type(),
            }),
        }
    }
}

impl<I> From<PrimitiveValue> for Value<I> {
    fn from(v: PrimitiveValue) -> Self {
        Value::Primitive(v)
    }
}

/// An enum representing a primitive value from a DICOM element. The result of decoding
/// an element's data value may be one of the enumerated types depending on its content
/// and value representation.
#[derive(Debug, PartialEq, Clone)]
pub enum PrimitiveValue {
    /// No data. Used for SQ (regardless of content) and any value of length 0.
    Empty,

    /// A sequence of strings.
    /// Used for AE, AS, PN, SH, CS, LO, UI and UC.
    /// Can also be used for IS, SS, DS, DA, DT and TM when decoding
    /// with format preservation.
    Strs(C<String>),

    /// A single string.
    /// Used for ST, LT, UT and UR, which are never multi-valued.
    Str(String),

    /// A sequence of attribute tags.
    /// Used specifically for AT.
    Tags(C<Tag>),

    /// The value is a sequence of unsigned 16-bit integers.
    /// Used for OB and UN.
    U8(C<u8>),

    /// The value is a sequence of signed 16-bit integers.
    /// Used for SS.
    I16(C<i16>),

    /// A sequence of unsigned 168-bit integers.
    /// Used for US and OW.
    U16(C<u16>),

    /// A sequence of signed 32-bit integers.
    /// Used for SL and IS.
    I32(C<i32>),

    /// A sequence of unsigned 32-bit integers.
    /// Used for UL and OL.
    U32(C<u32>),

    /// The value is a sequence of 32-bit floating point numbers.
    /// Used for OF and FL.
    F32(C<f32>),

    /// The value is a sequence of 64-bit floating point numbers.
    /// Used for OD and FD, DS.
    F64(C<f64>),

    /// A sequence of dates.
    /// Used for the DA representation.
    Date(C<NaiveDate>),

    /// A sequence of date-time values.
    /// Used for the DT representation.
    DateTime(C<DateTime<FixedOffset>>),

    /// A sequence of time values.
    /// Used for the TM representation.
    Time(C<NaiveTime>),
}

impl PrimitiveValue {

    /// Obtain the number of individual values.
    pub fn multiplicity(&self) -> u32 {
        use self::PrimitiveValue::*;
        match self {
            &Empty => 0,
            &Str(_) => 1,
            &Strs(ref c) => c.len() as u32,
            &Tags(ref c) => c.len() as u32,
            &U8(ref c) => c.len() as u32,
            &I16(ref c) => c.len() as u32,
            &U16(ref c) => c.len() as u32,
            &I32(ref c) => c.len() as u32,
            &U32(ref c) => c.len() as u32,
            &F32(ref c) => c.len() as u32,
            &F64(ref c) => c.len() as u32,
            &Date(ref c) => c.len() as u32,
            &DateTime(ref c) => c.len() as u32,
            &Time(ref c) => c.len() as u32,
        }
    }

    /// Get a single string value. If it contains multiple strings,
    /// only the first one is returned.
    pub fn string(&self) -> Option<&str> {
        use self::PrimitiveValue::*;
        match self {
            &Strs(ref c) => c.get(0).map(String::as_str),
            &Str(ref s) => Some(s),
            _ => None,
        }
    }

    /// Get a sequence of string values.
    pub fn strings(&self) -> Option<Vec<&str>> {
        use self::PrimitiveValue::*;
        match self {
            &Strs(ref c) => Some(c.iter().map(String::as_str).collect()),
            &Str(ref s) => Some(vec![&s]),
            _ => None,
        }
    }

    /// Get a single DICOM tag.
    pub fn tag(&self) -> Option<Tag> {
        use self::PrimitiveValue::*;
        match self {
            &Tags(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a sequence of DICOM tags.
    pub fn tags(&self) -> Option<&[Tag]> {
        use self::PrimitiveValue::*;
        match self {
            &Tags(ref c) => Some(&c),
            _ => None,
        }
    }

    /// Get a single 32-bit signed integer value.
    pub fn int32(&self) -> Option<i32> {
        use self::PrimitiveValue::*;
        match self {
            &I32(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 32-bit unsigned integer value.
    pub fn uint32(&self) -> Option<u32> {
        use self::PrimitiveValue::*;
        match self {
            &U32(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 16-bit signed integer value.
    pub fn int16(&self) -> Option<i16> {
        use self::PrimitiveValue::*;
        match self {
            &I16(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 16-bit unsigned integer value.
    pub fn uint16(&self) -> Option<u16> {
        use self::PrimitiveValue::*;
        match self {
            &U16(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 8-bit unsigned integer value.
    pub fn uint8(&self) -> Option<u8> {
        use self::PrimitiveValue::*;
        match self {
            &U8(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 32-bit floating point number value.
    pub fn float32(&self) -> Option<f32> {
        use self::PrimitiveValue::*;
        match self {
            &F32(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }

    /// Get a single 64-bit floating point number value.
    pub fn float64(&self) -> Option<f64> {
        use self::PrimitiveValue::*;
        match self {
            &F64(ref c) => c.get(0).map(Clone::clone),
            _ => None,
        }
    }
}

/// An enum representing an abstraction of a DICOM element's data value type.
/// This should be the equivalent of `PrimitiveValue` without the content,
/// plus the `Item` entry.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ValueType {
    /// No data. Used for any value of length 0.
    Empty,

    /// An item. Used for elements in a SQ, regardless of content.
    Item,

    /// A sequence of strings.
    /// Used for AE, AS, PN, SH, CS, LO, UI and UC.
    /// Can also be used for IS, SS, DS, DA, DT and TM when decoding
    /// with format preservation.
    Strs,

    /// A single string.
    /// Used for ST, LT, UT and UR, which are never multi-valued.
    Str,

    /// A sequence of attribute tags.
    /// Used specifically for AT.
    Tags,

    /// The value is a sequence of unsigned 16-bit integers.
    /// Used for OB and UN.
    U8,

    /// The value is a sequence of signed 16-bit integers.
    /// Used for SS.
    I16,

    /// A sequence of unsigned 168-bit integers.
    /// Used for US and OW.
    U16,

    /// A sequence of signed 32-bit integers.
    /// Used for SL and IS.
    I32,

    /// A sequence of unsigned 32-bit integers.
    /// Used for UL and OL.
    U32,

    /// The value is a sequence of 32-bit floating point numbers.
    /// Used for OF and FL.
    F32,

    /// The value is a sequence of 64-bit floating point numbers.
    /// Used for OD, FD and DS.
    F64,

    /// A sequence of dates.
    /// Used for the DA representation.
    Date,

    /// A sequence of date-time values.
    /// Used for the DT representation.
    DateTime,

    /// A sequence of time values.
    /// Used for the TM representation.
    Time,
}

/// A trait for a value that maps to a DICOM element data value.
pub trait DicomValueType {
    /// Retrieve the specific type of this value.
    fn value_type(&self) -> ValueType;

    /// Retrieve the number of values contained.
    fn size(&self) -> Length;

    /// Check whether the value is empty (0 length).
    fn is_empty(&self) -> bool {
        self.size() == Length(0)
    }
}

impl DicomValueType for PrimitiveValue {
    fn value_type(&self) -> ValueType {
        use self::PrimitiveValue::*;
        match *self {
            Empty => ValueType::Empty,
            Date(_) => ValueType::Date,
            DateTime(_) => ValueType::DateTime,
            F32(_) => ValueType::F32,
            F64(_) => ValueType::F64,
            I16(_) => ValueType::I16,
            I32(_) => ValueType::I32,
            Str(_) => ValueType::Str,
            Strs(_) => ValueType::Strs,
            Tags(_) => ValueType::Tags,
            Time(_) => ValueType::Time,
            U16(_) => ValueType::U16,
            U32(_) => ValueType::U32,
            U8(_) => ValueType::U8,
        }
    }

    fn size(&self) -> Length {
        use self::PrimitiveValue::*;
        Length::defined(match *self {
            Empty => 0,
            Str(_) => 1,
            Date(ref b) => b.len() as u32,
            DateTime(ref b) => b.len() as u32,
            F32(ref b) => b.len() as u32,
            F64(ref b) => b.len() as u32,
            I16(ref b) => b.len() as u32,
            I32(ref b) => b.len() as u32,
            Strs(ref b) => b.len() as u32,
            Tags(ref b) => b.len() as u32,
            Time(ref b) => b.len() as u32,
            U16(ref b) => b.len() as u32,
            U32(ref b) => b.len() as u32,
            U8(ref b) => b.len() as u32,
        })
    }
}

impl<I> DicomValueType for Value<I>
where
    I: DicomValueType,
{
    fn value_type(&self) -> ValueType {
        match *self {
            Value::Primitive(ref v) => v.value_type(),
            Value::Sequence { .. } => ValueType::Item,
        }
    }

    fn size(&self) -> Length {
        match *self {
            Value::Primitive(ref v) => v.size(),
            Value::Sequence { size, .. } => size,
        }
    }
}
<|endoftext|>


<commit_before>extern crate exonum;
extern crate exonum_testkit;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use exonum::helpers::{Height, ValidatorId};
use exonum_testkit::TestKitBuilder;
use exonum::blockchain::{Schema, ServiceContext};
use exonum::storage::StorageValue;

#[test]
fn test_add_to_validators() {
    let mut testkit = TestKitBuilder::auditor().with_validators(1).create();

    let proposal = {
        let mut cfg = testkit.actual_configuration();
        let mut validators = cfg.validators().to_vec();
        validators.push(testkit.network().us().clone());
        cfg.set_actual_from(Height(5));
        cfg.set_validators(validators);
        cfg
    };
    let stored = proposal.stored_configuration().clone();
    testkit.propose_configuration_change(proposal);

    testkit.create_blocks_until(Height(6));

    assert_eq!(testkit.network().us().validator_id(), Some(ValidatorId(1)));
    assert_eq!(testkit.network().validators()[1], testkit.network().us());
    assert_eq!(testkit.network().us().validator_id(), testkit.state().validator_id());
    assert_eq!(
        Schema::new(&testkit.snapshot()).actual_configuration(),
        stored
    );
    assert_eq!(
        Schema::new(&testkit.snapshot())
            .previous_configuration()
            .unwrap()
            .hash(),
        stored.previous_cfg_hash
    );
}

#[test]
fn test_exclude_from_validators() {
    let mut testkit = TestKitBuilder::validator().with_validators(2).create();

    let proposal = {
        let mut cfg = testkit.actual_configuration();
        let validator = cfg.validators()[1].clone();
        cfg.set_actual_from(Height(5));
        cfg.set_validators(vec![validator]);
        cfg
    };
    let stored = proposal.stored_configuration().clone();
    testkit.propose_configuration_change(proposal);

    testkit.create_blocks_until(Height(6));

    assert_eq!(testkit.network().us().validator_id(), None);
    assert_eq!(testkit.network().validators().len(), 1);
    assert_eq!(testkit.network().us().validator_id(), testkit.state().validator_id());
    assert_eq!(
        Schema::new(&testkit.snapshot()).actual_configuration(),
        stored
    );
    assert_eq!(
        Schema::new(&testkit.snapshot())
            .previous_configuration()
            .unwrap()
            .hash(),
        stored.previous_cfg_hash
    );
}

#[test]
fn test_change_service_config() {
    #[derive(Debug, Serialize, Deserialize, Clone)]
    struct ServiceConfig {
        name: String,
        value: u64,
    };

    let service_cfg = ServiceConfig {
        name: String::from("Config"),
        value: 64,
    };

    let mut testkit = TestKitBuilder::validator().create();
    let proposal = {
        let mut cfg = testkit.actual_configuration();
        cfg.set_service_config("my_service", service_cfg.clone());
        cfg.set_actual_from(Height(5));
        cfg
    };
    testkit.propose_configuration_change(proposal);

    testkit.create_blocks_until(Height(6));

    assert_eq!(
        serde_json::to_value(service_cfg).unwrap(),
        Schema::new(&testkit.snapshot())
            .actual_configuration()
            .services["my_service"]
    );
}
<commit_msg>Format code<commit_after>extern crate exonum;
extern crate exonum_testkit;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use exonum::helpers::{Height, ValidatorId};
use exonum_testkit::TestKitBuilder;
use exonum::blockchain::{Schema, ServiceContext};
use exonum::storage::StorageValue;

#[test]
fn test_add_to_validators() {
    let mut testkit = TestKitBuilder::auditor().with_validators(1).create();

    let proposal = {
        let mut cfg = testkit.actual_configuration();
        let mut validators = cfg.validators().to_vec();
        validators.push(testkit.network().us().clone());
        cfg.set_actual_from(Height(5));
        cfg.set_validators(validators);
        cfg
    };
    let stored = proposal.stored_configuration().clone();
    testkit.propose_configuration_change(proposal);

    testkit.create_blocks_until(Height(6));

    assert_eq!(testkit.network().us().validator_id(), Some(ValidatorId(1)));
    assert_eq!(testkit.network().validators()[1], testkit.network().us());
    assert_eq!(
        testkit.network().us().validator_id(),
        testkit.state().validator_id()
    );
    assert_eq!(
        Schema::new(&testkit.snapshot()).actual_configuration(),
        stored
    );
    assert_eq!(
        Schema::new(&testkit.snapshot())
            .previous_configuration()
            .unwrap()
            .hash(),
        stored.previous_cfg_hash
    );
}

#[test]
fn test_exclude_from_validators() {
    let mut testkit = TestKitBuilder::validator().with_validators(2).create();

    let proposal = {
        let mut cfg = testkit.actual_configuration();
        let validator = cfg.validators()[1].clone();
        cfg.set_actual_from(Height(5));
        cfg.set_validators(vec![validator]);
        cfg
    };
    let stored = proposal.stored_configuration().clone();
    testkit.propose_configuration_change(proposal);

    testkit.create_blocks_until(Height(6));

    assert_eq!(testkit.network().us().validator_id(), None);
    assert_eq!(testkit.network().validators().len(), 1);
    assert_eq!(
        testkit.network().us().validator_id(),
        testkit.state().validator_id()
    );
    assert_eq!(
        Schema::new(&testkit.snapshot()).actual_configuration(),
        stored
    );
    assert_eq!(
        Schema::new(&testkit.snapshot())
            .previous_configuration()
            .unwrap()
            .hash(),
        stored.previous_cfg_hash
    );
}

#[test]
fn test_change_service_config() {
    #[derive(Debug, Serialize, Deserialize, Clone)]
    struct ServiceConfig {
        name: String,
        value: u64,
    };

    let service_cfg = ServiceConfig {
        name: String::from("Config"),
        value: 64,
    };

    let mut testkit = TestKitBuilder::validator().create();
    let proposal = {
        let mut cfg = testkit.actual_configuration();
        cfg.set_service_config("my_service", service_cfg.clone());
        cfg.set_actual_from(Height(5));
        cfg
    };
    testkit.propose_configuration_change(proposal);

    testkit.create_blocks_until(Height(6));

    assert_eq!(
        serde_json::to_value(service_cfg).unwrap(),
        Schema::new(&testkit.snapshot())
            .actual_configuration()
            .services["my_service"]
    );
}
<|endoftext|>