<commit_before>use dicom::core::smallvec;
use dicom::{core::dicom_value, dictionary_std::tags};
use dicom::{
    core::{DataElement, PrimitiveValue, VR},
    encoding::transfer_syntax,
    object::{mem::InMemDicomObject, open_file, StandardDataDictionary},
    transfer_syntax::TransferSyntaxRegistry,
};
use dicom_ul::pdu::Pdu;
use dicom_ul::{
    association::ClientAssociationOptions,
    pdu::{PDataValue, PDataValueType},
};
use smallvec::smallvec;
use std::ffi::OsStr;
use std::io::Write;
use std::path::PathBuf;
use structopt::StructOpt;
use transfer_syntax::TransferSyntaxIndex;
use std::collections::HashSet;
use walkdir::WalkDir;
use indicatif::{ProgressBar, ProgressStyle};

/// DICOM C-STORE SCU
#[derive(Debug, StructOpt)]
struct App {
    /// socket address to STORE SCP (example: "127.0.0.1:104")
    addr: String,
    /// the DICOM file(s) to store
    files: Vec<PathBuf>,
    /// verbose mode
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,
    /// the C-STORE message ID
    #[structopt(short = "m", long = "message-id", default_value = "1")]
    message_id: u16,
    /// the calling AE title
    #[structopt(long = "calling-ae-title", default_value = "STORE-SCU")]
    calling_ae_title: String,
    /// the called AE title
    #[structopt(long = "called-ae-title", default_value = "ANY-SCP")]
    called_ae_title: String,
    /// the maximum PDU length accepted by the SCU
    #[structopt(long = "max-pdu-length", default_value = "16384")]
    max_pdu_length: u32,
    /// fail if not all DICOM files can be transferred
    #[structopt(long = "fail-first")]
    fail_first: bool,
}

struct DicomFile {
    /// File path
    file: PathBuf,
    /// Storage SOP Class UID
    sop_class_uid: String,
    /// Storage SOP Instance UID
    sop_instance_uid: String,
    /// File Transfer Syntax
    file_transfer_syntax: String,
    /// Transfer Syntax selected
    ts_selected: Option<String>,
    /// Presentation Context selected
    pc_selected: Option<dicom_ul::pdu::PresentationContextResult>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let App {
        addr,
        files,
        verbose,
        message_id,
        calling_ae_title,
        called_ae_title,
        max_pdu_length,
        fail_first,
    } = App::from_args();

    let mut checked_files: Vec<PathBuf> = vec![];
    let mut dicom_files: Vec<DicomFile> = vec![];
    let mut presentation_contexts = HashSet::new();

    for file in files {

        if file.is_dir() {
            for file in WalkDir::new(file.as_path())
                                    .into_iter()
                                    .filter_map(Result::ok)
                                    .filter(|f| !f.file_type().is_dir()) {
                                        checked_files.push(file.into_path());
                                    }
        }
        else {
            checked_files.push(file);
        }
    }

    for file in checked_files {

        if verbose {
            println!("Opening file '{}'...", file.display());
        }

        match check_file(file) {
            Ok(dicom_file) => {
                presentation_contexts.insert((dicom_file.sop_class_uid.to_string(),dicom_file.file_transfer_syntax.clone()));
                dicom_files.push(dicom_file);
            },
            Err(e) => {
                if verbose {
                    println!("Error: {}", e);
                }
            }
        }
    }

    if dicom_files.is_empty() {
        eprintln!("No supported files to transfer");
        std::process::exit(-1);
    }

    if verbose {
        println!("Establishing association with '{}'...", &addr);
    }

    let mut scu_init = ClientAssociationOptions::new();

    for (storage_sop_class_uid,transfer_syntax) in &presentation_contexts {
        scu_init = scu_init.with_abstract_syntax(storage_sop_class_uid)
                    .with_transfer_syntax(transfer_syntax);
    }
    let mut scu = scu_init.calling_ae_title(calling_ae_title)
                    .called_ae_title(called_ae_title)
                    .max_pdu_length(max_pdu_length)
                    .establish(addr)?;

    if verbose {
        println!("Association established");
    }

    for mut file in &mut dicom_files {
        // TODO(#106) transfer syntax conversion is currently not supported
        match check_presentation_contexts(file, scu.presentation_contexts()) {
            Ok((pc, ts)) => {
                file.pc_selected = Some(pc);
                file.ts_selected = Some(ts);
            },
            Err(e) => {
                eprintln!("Could not choose a transfer syntax: {}", e);
                if fail_first {
                    let _ = scu.abort();
                    std::process::exit(-2);
                }
            }
        }
    }

    let progress_bar;
    if !verbose {
        progress_bar = Some(ProgressBar::new(dicom_files.len() as u64));
        if let Some(pb) = progress_bar.as_ref() {
            pb.set_style(ProgressStyle::default_bar()
              .template("[{elapsed_precise}] {bar:40} {pos}/{len} {msg}")) };
    } else {
        progress_bar = None;
    }

    for file in dicom_files {

        if let (Some(pc_selected),Some(ts_selected)) = (file.pc_selected, file.ts_selected) {

            let cmd = store_req_command(
                &file.sop_class_uid,
                &file.sop_instance_uid,
                message_id,
            );

            let mut cmd_data = Vec::with_capacity(128);
            cmd.write_dataset_with_ts(
                &mut cmd_data,
                &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
            )?;

            let mut object_data = Vec::with_capacity(2048);
            let dicom_file = open_file(file.file)?;
            let ts_selected = TransferSyntaxRegistry.get(&ts_selected).ok_or("Unsupported file transfer syntax")?;
            dicom_file.write_dataset_with_ts(&mut object_data, ts_selected)?;

            let nbytes = cmd_data.len() + object_data.len();

            if verbose {
                println!("Sending payload (~ {} kB)...", nbytes / 1_000);
            }

            if nbytes < scu.acceptor_max_pdu_length() as usize - 100 {
                let pdu = Pdu::PData {
                    data: vec![
                        PDataValue {
                            presentation_context_id: pc_selected.id,
                            value_type: PDataValueType::Command,
                            is_last: true,
                            data: cmd_data,
                        },
                        PDataValue {
                            presentation_context_id: pc_selected.id,
                            value_type: PDataValueType::Data,
                            is_last: true,
                            data: object_data,
                        },
                    ],
                };

                scu.send(&pdu)?;
            } else {
                let pdu = Pdu::PData {
                    data: vec![PDataValue {
                        presentation_context_id: pc_selected.id,
                        value_type: PDataValueType::Command,
                        is_last: true,
                        data: cmd_data,
                    }],
                };

                scu.send(&pdu)?;

                {
                    let mut pdata = scu.send_pdata(pc_selected.id);
                    pdata.write_all(&object_data)?;
                }
            }

            if verbose {
                println!("Awaiting response...");
            }

            let rsp_pdu = scu.receive()?;

            match rsp_pdu {
                Pdu::PData { data } => {
                    let data_value = &data[0];

                    let cmd_obj = InMemDicomObject::read_dataset_with_ts(
                        &data_value.data[..],
                        &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
                    )?;
                    if verbose {
                        println!("Response: {:?}", cmd_obj);
                    }
                    let status = cmd_obj.element(tags::STATUS)?.to_int::<u16>()?;
                    let storage_sop_instance_uid =
                        file.sop_instance_uid.trim_end_matches(|c: char| c.is_whitespace() || c == '\0');
                    if status == 0 {
                        if verbose {
                            println!("Successfully stored instance `{}`", storage_sop_instance_uid);
                        }
                    } else {
                        println!(
                            "Failed to store instance `{}` (status code {})",
                            storage_sop_instance_uid, status
                        );
                        if fail_first {
                            let _ = scu.abort();
                            std::process::exit(-2);
                        }
                    }
                }

                pdu @ Pdu::Unknown { .. }
                | pdu @ Pdu::AssociationRQ { .. }
                | pdu @ Pdu::AssociationAC { .. }
                | pdu @ Pdu::AssociationRJ { .. }
                | pdu @ Pdu::ReleaseRQ
                | pdu @ Pdu::ReleaseRP
                | pdu @ Pdu::AbortRQ { .. } => {
                    eprintln!("Unexpected SCP response: {:?}", pdu);
                    let _ = scu.abort();
                    std::process::exit(-2);
                }
            }
        }
        if let Some(pb) = progress_bar.as_ref() { pb.inc(1) };
    }

    if let Some(pb) = progress_bar { pb.finish_with_message("done") };

scu.release()?;
    Ok(())
}

fn store_req_command(
    storage_sop_class_uid: &str,
    storage_sop_instance_uid: &str,
    message_id: u16,
) -> InMemDicomObject<StandardDataDictionary> {
    let mut obj = InMemDicomObject::create_empty();

    // group length
    obj.put(DataElement::new(
        tags::COMMAND_GROUP_LENGTH,
        VR::UL,
        PrimitiveValue::from(
            12 + 8
                + even_len(storage_sop_class_uid.len())
                + 10
                + 10
                + 10
                + 10
                + 8
                + even_len(storage_sop_instance_uid.len()),
        ),
    ));

    // SOP Class UID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_CLASS_UID,
        VR::UI,
        dicom_value!(Str, storage_sop_class_uid),
    ));

    // command field
    obj.put(DataElement::new(
        tags::COMMAND_FIELD,
        VR::US,
        dicom_value!(U16, [0x0001]),
    ));

    // message ID
    obj.put(DataElement::new(
        tags::MESSAGE_ID,
        VR::US,
        dicom_value!(U16, [message_id]),
    ));

    //priority
    obj.put(DataElement::new(
        tags::PRIORITY,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // data set type
    obj.put(DataElement::new(
        tags::COMMAND_DATA_SET_TYPE,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // affected SOP Instance UID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_INSTANCE_UID,
        VR::UI,
        dicom_value!(Str, storage_sop_instance_uid),
    ));

    obj
}

fn even_len(l: usize) -> u32 {
    ((l + 1) & !1) as u32
}

fn check_file(file: PathBuf) -> Result<DicomFile, Box<dyn std::error::Error>> {
    // Ignore DICOMDIR files until better support is added
    let _ = (file.file_name() != Some(OsStr::new("DICOMDIR"))).then(|| false).ok_or("DICOMDIR file not supported")?;
    let dicom_file = open_file(&file)?;

    let meta = dicom_file.meta();

    let storage_sop_class_uid = &meta.media_storage_sop_class_uid;
    let storage_sop_instance_uid = &meta.media_storage_sop_instance_uid;
    let transfer_syntax_uid = &meta.transfer_syntax.trim_end_matches('\0');
    let ts = TransferSyntaxRegistry.get(transfer_syntax_uid).ok_or("Unsupported file transfer syntax")?;
    Ok(DicomFile{file,
                 sop_class_uid: storage_sop_class_uid.to_string(),
                 sop_instance_uid: storage_sop_instance_uid.to_string(),
                 file_transfer_syntax: String::from(ts.uid()),
                 ts_selected: None,
                 pc_selected: None,})
}

fn check_presentation_contexts(file: &DicomFile, pcs: &[dicom_ul::pdu::PresentationContextResult]) -> Result<(dicom_ul::pdu::PresentationContextResult, String), Box<dyn std::error::Error>> {
    let file_ts = TransferSyntaxRegistry.get(&file.file_transfer_syntax).ok_or("Unsupported file transfer syntax")?;
    // TODO(#106) transfer syntax conversion is currently not supported
    let pc = pcs.iter().find(|pc| {
        // Check support for this transfer syntax.
        // If it is the same as the file, we're good.
        // Otherwise, uncompressed data set encoding
        // and native pixel data is required on both ends.
        let ts = &pc.transfer_syntax;
        ts == file_ts.uid()
            || TransferSyntaxRegistry
               .get(&pc.transfer_syntax)
               .filter(|ts| file_ts.is_codec_free() && ts.is_codec_free())
               .map(|_| true)
               .unwrap_or(false)
    }).ok_or("No presentation context accepted")?;
    let ts = TransferSyntaxRegistry
             .get(&pc.transfer_syntax)
             .ok_or("Poorly negotiated transfer syntax")?;

    Ok((pc.clone(), String::from(ts.uid())))
}

#[cfg(test)]
mod tests {
    use super::even_len;
    #[test]
    fn test_even_len() {
        assert_eq!(even_len(0), 0);
        assert_eq!(even_len(1), 2);
        assert_eq!(even_len(2), 2);
        assert_eq!(even_len(3), 4);
        assert_eq!(even_len(4), 4);
        assert_eq!(even_len(5), 6);
    }
}
<commit_msg>Update error message and improve file check speed<commit_after>use dicom::core::smallvec;
use dicom::{core::dicom_value, dictionary_std::tags};
use dicom::{
    core::{DataElement, header::Tag, PrimitiveValue, VR},
    encoding::transfer_syntax,
    object::{mem::InMemDicomObject, open_file, StandardDataDictionary},
    transfer_syntax::TransferSyntaxRegistry,
};
use dicom_ul::pdu::Pdu;
use dicom_ul::{
    association::ClientAssociationOptions,
    pdu::{PDataValue, PDataValueType},
};
use smallvec::smallvec;
use std::ffi::OsStr;
use std::io::Write;
use std::path::{Path, PathBuf};
use structopt::StructOpt;
use transfer_syntax::TransferSyntaxIndex;
use std::collections::HashSet;
use walkdir::WalkDir;
use indicatif::{ProgressBar, ProgressStyle};

/// DICOM C-STORE SCU
#[derive(Debug, StructOpt)]
struct App {
    /// socket address to STORE SCP (example: "127.0.0.1:104")
    addr: String,
    /// the DICOM file(s) to store
    files: Vec<PathBuf>,
    /// verbose mode
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,
    /// the C-STORE message ID
    #[structopt(short = "m", long = "message-id", default_value = "1")]
    message_id: u16,
    /// the calling AE title
    #[structopt(long = "calling-ae-title", default_value = "STORE-SCU")]
    calling_ae_title: String,
    /// the called AE title
    #[structopt(long = "called-ae-title", default_value = "ANY-SCP")]
    called_ae_title: String,
    /// the maximum PDU length accepted by the SCU
    #[structopt(long = "max-pdu-length", default_value = "16384")]
    max_pdu_length: u32,
    /// fail if not all DICOM files can be transferred
    #[structopt(long = "fail-first")]
    fail_first: bool,
}

struct DicomFile {
    /// File path
    file: PathBuf,
    /// Storage SOP Class UID
    sop_class_uid: String,
    /// Storage SOP Instance UID
    sop_instance_uid: String,
    /// File Transfer Syntax
    file_transfer_syntax: String,
    /// Transfer Syntax selected
    ts_selected: Option<String>,
    /// Presentation Context selected
    pc_selected: Option<dicom_ul::pdu::PresentationContextResult>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let App {
        addr,
        files,
        verbose,
        message_id,
        calling_ae_title,
        called_ae_title,
        max_pdu_length,
        fail_first,
    } = App::from_args();

    let mut checked_files: Vec<PathBuf> = vec![];
    let mut dicom_files: Vec<DicomFile> = vec![];
    let mut presentation_contexts = HashSet::new();

    for file in files {

        if file.is_dir() {
            for file in WalkDir::new(file.as_path())
                                    .into_iter()
                                    .filter_map(Result::ok)
                                    .filter(|f| !f.file_type().is_dir()) {
                                        checked_files.push(file.into_path());
                                    }
        }
        else {
            checked_files.push(file);
        }
    }

    for file in checked_files {

        if verbose {
            println!("Opening file '{}'...", file.display());
        }

        match check_file(&file) {
            Ok(dicom_file) => {
                presentation_contexts.insert((dicom_file.sop_class_uid.to_string(),dicom_file.file_transfer_syntax.clone()));
                dicom_files.push(dicom_file);
            },
            Err(e) => {
                if verbose {
                    println!("Could not open file {}: {}", file.display(), e);
                }
            }
        }
    }

    if dicom_files.is_empty() {
        eprintln!("No supported files to transfer");
        std::process::exit(-1);
    }

    if verbose {
        println!("Establishing association with '{}'...", &addr);
    }

    let mut scu_init = ClientAssociationOptions::new();

    for (storage_sop_class_uid,transfer_syntax) in &presentation_contexts {
        scu_init = scu_init.with_abstract_syntax(storage_sop_class_uid)
                    .with_transfer_syntax(transfer_syntax);
    }
    let mut scu = scu_init.calling_ae_title(calling_ae_title)
                    .called_ae_title(called_ae_title)
                    .max_pdu_length(max_pdu_length)
                    .establish(addr)?;

    if verbose {
        println!("Association established");
    }

    for mut file in &mut dicom_files {
        // TODO(#106) transfer syntax conversion is currently not supported
        match check_presentation_contexts(file, scu.presentation_contexts()) {
            Ok((pc, ts)) => {
                file.pc_selected = Some(pc);
                file.ts_selected = Some(ts);
            },
            Err(e) => {
                eprintln!("Could not choose a transfer syntax: {}", e);
                if fail_first {
                    let _ = scu.abort();
                    std::process::exit(-2);
                }
            }
        }
    }

    let progress_bar;
    if !verbose {
        progress_bar = Some(ProgressBar::new(dicom_files.len() as u64));
        if let Some(pb) = progress_bar.as_ref() {
            pb.set_style(ProgressStyle::default_bar()
              .template("[{elapsed_precise}] {bar:40} {pos}/{len} {msg}")) };
    } else {
        progress_bar = None;
    }

    for file in dicom_files {

        if let (Some(pc_selected),Some(ts_selected)) = (file.pc_selected, file.ts_selected) {

            let cmd = store_req_command(
                &file.sop_class_uid,
                &file.sop_instance_uid,
                message_id,
            );

            let mut cmd_data = Vec::with_capacity(128);
            cmd.write_dataset_with_ts(
                &mut cmd_data,
                &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
            )?;

            let mut object_data = Vec::with_capacity(2048);
            let dicom_file = open_file(file.file)?;
            let ts_selected = TransferSyntaxRegistry.get(&ts_selected).ok_or("Unsupported file transfer syntax")?;
            dicom_file.write_dataset_with_ts(&mut object_data, ts_selected)?;

            let nbytes = cmd_data.len() + object_data.len();

            if verbose {
                println!("Sending payload (~ {} kB)...", nbytes / 1_000);
            }

            if nbytes < scu.acceptor_max_pdu_length() as usize - 100 {
                let pdu = Pdu::PData {
                    data: vec![
                        PDataValue {
                            presentation_context_id: pc_selected.id,
                            value_type: PDataValueType::Command,
                            is_last: true,
                            data: cmd_data,
                        },
                        PDataValue {
                            presentation_context_id: pc_selected.id,
                            value_type: PDataValueType::Data,
                            is_last: true,
                            data: object_data,
                        },
                    ],
                };

                scu.send(&pdu)?;
            } else {
                let pdu = Pdu::PData {
                    data: vec![PDataValue {
                        presentation_context_id: pc_selected.id,
                        value_type: PDataValueType::Command,
                        is_last: true,
                        data: cmd_data,
                    }],
                };

                scu.send(&pdu)?;

                {
                    let mut pdata = scu.send_pdata(pc_selected.id);
                    pdata.write_all(&object_data)?;
                }
            }

            if verbose {
                println!("Awaiting response...");
            }

            let rsp_pdu = scu.receive()?;

            match rsp_pdu {
                Pdu::PData { data } => {
                    let data_value = &data[0];

                    let cmd_obj = InMemDicomObject::read_dataset_with_ts(
                        &data_value.data[..],
                        &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
                    )?;
                    if verbose {
                        println!("Response: {:?}", cmd_obj);
                    }
                    let status = cmd_obj.element(tags::STATUS)?.to_int::<u16>()?;
                    let storage_sop_instance_uid =
                        file.sop_instance_uid.trim_end_matches(|c: char| c.is_whitespace() || c == '\0');
                    if status == 0 {
                        if verbose {
                            println!("Successfully stored instance `{}`", storage_sop_instance_uid);
                        }
                    } else {
                        println!(
                            "Failed to store instance `{}` (status code {})",
                            storage_sop_instance_uid, status
                        );
                        if fail_first {
                            let _ = scu.abort();
                            std::process::exit(-2);
                        }
                    }
                }

                pdu @ Pdu::Unknown { .. }
                | pdu @ Pdu::AssociationRQ { .. }
                | pdu @ Pdu::AssociationAC { .. }
                | pdu @ Pdu::AssociationRJ { .. }
                | pdu @ Pdu::ReleaseRQ
                | pdu @ Pdu::ReleaseRP
                | pdu @ Pdu::AbortRQ { .. } => {
                    eprintln!("Unexpected SCP response: {:?}", pdu);
                    let _ = scu.abort();
                    std::process::exit(-2);
                }
            }
        }
        if let Some(pb) = progress_bar.as_ref() { pb.inc(1) };
    }

    if let Some(pb) = progress_bar { pb.finish_with_message("done") };

scu.release()?;
    Ok(())
}

fn store_req_command(
    storage_sop_class_uid: &str,
    storage_sop_instance_uid: &str,
    message_id: u16,
) -> InMemDicomObject<StandardDataDictionary> {
    let mut obj = InMemDicomObject::create_empty();

    // group length
    obj.put(DataElement::new(
        tags::COMMAND_GROUP_LENGTH,
        VR::UL,
        PrimitiveValue::from(
            12 + 8
                + even_len(storage_sop_class_uid.len())
                + 10
                + 10
                + 10
                + 10
                + 8
                + even_len(storage_sop_instance_uid.len()),
        ),
    ));

    // SOP Class UID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_CLASS_UID,
        VR::UI,
        dicom_value!(Str, storage_sop_class_uid),
    ));

    // command field
    obj.put(DataElement::new(
        tags::COMMAND_FIELD,
        VR::US,
        dicom_value!(U16, [0x0001]),
    ));

    // message ID
    obj.put(DataElement::new(
        tags::MESSAGE_ID,
        VR::US,
        dicom_value!(U16, [message_id]),
    ));

    //priority
    obj.put(DataElement::new(
        tags::PRIORITY,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // data set type
    obj.put(DataElement::new(
        tags::COMMAND_DATA_SET_TYPE,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // affected SOP Instance UID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_INSTANCE_UID,
        VR::UI,
        dicom_value!(Str, storage_sop_instance_uid),
    ));

    obj
}

fn even_len(l: usize) -> u32 {
    ((l + 1) & !1) as u32
}

fn check_file(file: &Path) -> Result<DicomFile, Box<dyn std::error::Error>> {
    // Ignore DICOMDIR files until better support is added
    let _ = (file.file_name() != Some(OsStr::new("DICOMDIR"))).then(|| false).ok_or("DICOMDIR file not supported")?;
    let dicom_file = dicom::object::OpenFileOptions::new()
                        .read_until(Tag(0x0001,0x000))
                        .open_file(&file)?;

    let meta = dicom_file.meta();

    let storage_sop_class_uid = &meta.media_storage_sop_class_uid;
    let storage_sop_instance_uid = &meta.media_storage_sop_instance_uid;
    let transfer_syntax_uid = &meta.transfer_syntax.trim_end_matches('\0');
    let ts = TransferSyntaxRegistry.get(transfer_syntax_uid).ok_or("Unsupported file transfer syntax")?;
    Ok(DicomFile{file: file.to_path_buf(),
                 sop_class_uid: storage_sop_class_uid.to_string(),
                 sop_instance_uid: storage_sop_instance_uid.to_string(),
                 file_transfer_syntax: String::from(ts.uid()),
                 ts_selected: None,
                 pc_selected: None,})
}

fn check_presentation_contexts(file: &DicomFile, pcs: &[dicom_ul::pdu::PresentationContextResult]) -> Result<(dicom_ul::pdu::PresentationContextResult, String), Box<dyn std::error::Error>> {
    let file_ts = TransferSyntaxRegistry.get(&file.file_transfer_syntax).ok_or("Unsupported file transfer syntax")?;
    // TODO(#106) transfer syntax conversion is currently not supported
    let pc = pcs.iter().find(|pc| {
        // Check support for this transfer syntax.
        // If it is the same as the file, we're good.
        // Otherwise, uncompressed data set encoding
        // and native pixel data is required on both ends.
        let ts = &pc.transfer_syntax;
        ts == file_ts.uid()
            || TransferSyntaxRegistry
               .get(&pc.transfer_syntax)
               .filter(|ts| file_ts.is_codec_free() && ts.is_codec_free())
               .map(|_| true)
               .unwrap_or(false)
    }).ok_or("No presentation context accepted")?;
    let ts = TransferSyntaxRegistry
             .get(&pc.transfer_syntax)
             .ok_or("Poorly negotiated transfer syntax")?;

    Ok((pc.clone(), String::from(ts.uid())))
}

#[cfg(test)]
mod tests {
    use super::even_len;
    #[test]
    fn test_even_len() {
        assert_eq!(even_len(0), 0);
        assert_eq!(even_len(1), 2);
        assert_eq!(even_len(2), 2);
        assert_eq!(even_len(3), 4);
        assert_eq!(even_len(4), 4);
        assert_eq!(even_len(5), 6);
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-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.

use CodeSuggestion;
use Substitution;
use Level;
use RenderSpan;
use std::fmt;
use syntax_pos::{MultiSpan, Span};
use snippet::Style;

#[must_use]
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Diagnostic {
    pub level: Level,
    pub message: Vec<(String, Style)>,
    pub code: Option<String>,
    pub span: MultiSpan,
    pub children: Vec<SubDiagnostic>,
    pub suggestions: Vec<CodeSuggestion>,
}

/// For example a note attached to an error.
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct SubDiagnostic {
    pub level: Level,
    pub message: Vec<(String, Style)>,
    pub span: MultiSpan,
    pub render_span: Option<RenderSpan>,
}

#[derive(PartialEq, Eq)]
pub struct DiagnosticStyledString(pub Vec<StringPart>);

impl DiagnosticStyledString {
    pub fn new() -> DiagnosticStyledString {
        DiagnosticStyledString(vec![])
    }
    pub fn push_normal<S: Into<String>>(&mut self, t: S) {
        self.0.push(StringPart::Normal(t.into()));
    }
    pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
        self.0.push(StringPart::Highlighted(t.into()));
    }
    pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
        DiagnosticStyledString(vec![StringPart::Normal(t.into())])
    }

    pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
        DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
    }

    pub fn content(&self) -> String {
        self.0.iter().map(|x| x.content()).collect::<String>()
    }
}

#[derive(PartialEq, Eq)]
pub enum StringPart {
    Normal(String),
    Highlighted(String),
}

impl StringPart {
    pub fn content(&self) -> String {
        match self {
            &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned()
        }
    }
}

impl Diagnostic {
    pub fn new(level: Level, message: &str) -> Self {
        Diagnostic::new_with_code(level, None, message)
    }

    pub fn new_with_code(level: Level, code: Option<String>, message: &str) -> Self {
        Diagnostic {
            level,
            message: vec![(message.to_owned(), Style::NoStyle)],
            code,
            span: MultiSpan::new(),
            children: vec![],
            suggestions: vec![],
        }
    }

    /// Cancel the diagnostic (a structured diagnostic must either be emitted or
    /// canceled or it will panic when dropped).
    /// BEWARE: if this DiagnosticBuilder is an error, then creating it will
    /// bump the error count on the Handler and canceling it won't undo that.
    /// If you want to decrement the error count you should use `Handler::cancel`.
    pub fn cancel(&mut self) {
        self.level = Level::Cancelled;
    }

    pub fn cancelled(&self) -> bool {
        self.level == Level::Cancelled
    }

    /// Add a span/label to be included in the resulting snippet.
    /// This is pushed onto the `MultiSpan` that was created when the
    /// diagnostic was first built. If you don't call this function at
    /// all, and you just supplied a `Span` to create the diagnostic,
    /// then the snippet will just include that `Span`, which is
    /// called the primary span.
    pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
        self.span.push_span_label(span, label.into());
        self
    }

    pub fn note_expected_found(&mut self,
                               label: &fmt::Display,
                               expected: DiagnosticStyledString,
                               found: DiagnosticStyledString)
                               -> &mut Self
    {
        self.note_expected_found_extra(label, expected, found, &"", &"")
    }

    pub fn note_expected_found_extra(&mut self,
                                     label: &fmt::Display,
                                     expected: DiagnosticStyledString,
                                     found: DiagnosticStyledString,
                                     expected_extra: &fmt::Display,
                                     found_extra: &fmt::Display)
                                     -> &mut Self
    {
        let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
        msg.extend(expected.0.iter()
                   .map(|x| match *x {
                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
                   }));
        msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
        msg.push((format!("   found {} `", label), Style::NoStyle));
        msg.extend(found.0.iter()
                   .map(|x| match *x {
                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
                   }));
        msg.push((format!("`{}", found_extra), Style::NoStyle));

        // For now, just attach these as notes
        self.highlighted_note(msg);
        self
    }

    pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
        self.highlighted_note(vec![
            (format!("`{}` from trait: `", name), Style::NoStyle),
            (signature, Style::Highlight),
            ("`".to_string(), Style::NoStyle)]);
        self
    }

    pub fn note(&mut self, msg: &str) -> &mut Self {
        self.sub(Level::Note, msg, MultiSpan::new(), None);
        self
    }

    pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
        self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_note<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Note, msg, sp.into(), None);
        self
    }

    pub fn warn(&mut self, msg: &str) -> &mut Self {
        self.sub(Level::Warning, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_warn<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Warning, msg, sp.into(), None);
        self
    }

    pub fn help(&mut self , msg: &str) -> &mut Self {
        self.sub(Level::Help, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_help<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Help, msg, sp.into(), None);
        self
    }

    /// Prints out a message with a suggested edit of the code. If the suggestion is presented
    /// inline it will only show the text message and not the text.
    ///
    /// See `CodeSuggestion` for more information.
    pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitution_parts: vec![Substitution {
                span: sp,
                substitutions: vec![suggestion],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: false,
        });
        self
    }

    /// Prints out a message with a suggested edit of the code.
    ///
    /// In case of short messages and a simple suggestion,
    /// rustc displays it as a label like
    ///
    /// "try adding parentheses: `(tup.0).1`"
    ///
    /// The message
    /// * should not end in any punctuation (a `:` is added automatically)
    /// * should not be a question
    /// * should not contain any parts like "the following", "as shown"
    /// * may look like "to do xyz, use" or "to do xyz, use abc"
    /// * may contain a name of a function, variable or type, but not whole expressions
    ///
    /// See `CodeSuggestion` for more information.
    pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitution_parts: vec![Substitution {
                span: sp,
                substitutions: vec![suggestion],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
        });
        self
    }

    pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitution_parts: vec![Substitution {
                span: sp,
                substitutions: suggestions,
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
        });
        self
    }

    pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
        self.span = sp.into();
        self
    }

    pub fn code(&mut self, s: String) -> &mut Self {
        self.code = Some(s);
        self
    }

    pub fn message(&self) -> String {
        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
    }

    pub fn styled_message(&self) -> &Vec<(String, Style)> {
        &self.message
    }

    /// Used by a lint. Copies over all details *but* the "main
    /// message".
    pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
        self.span = from.span.clone();
        self.code = from.code.clone();
        self.children.extend(from.children.iter().cloned())
    }

    /// Convenience function for internal use, clients should use one of the
    /// public methods above.
    pub(crate) fn sub(&mut self,
           level: Level,
           message: &str,
           span: MultiSpan,
           render_span: Option<RenderSpan>) {
        let sub = SubDiagnostic {
            level,
            message: vec![(message.to_owned(), Style::NoStyle)],
            span,
            render_span,
        };
        self.children.push(sub);
    }

    /// Convenience function for internal use, clients should use one of the
    /// public methods above.
    fn sub_with_highlights(&mut self,
                           level: Level,
                           message: Vec<(String, Style)>,
                           span: MultiSpan,
                           render_span: Option<RenderSpan>) {
        let sub = SubDiagnostic {
            level,
            message,
            span,
            render_span,
        };
        self.children.push(sub);
    }
}

impl SubDiagnostic {
    pub fn message(&self) -> String {
        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
    }

    pub fn styled_message(&self) -> &Vec<(String, Style)> {
        &self.message
    }
}
<commit_msg>Update docs for Diagnostic::span_suggestion(s)<commit_after>// Copyright 2012-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.

use CodeSuggestion;
use Substitution;
use Level;
use RenderSpan;
use std::fmt;
use syntax_pos::{MultiSpan, Span};
use snippet::Style;

#[must_use]
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Diagnostic {
    pub level: Level,
    pub message: Vec<(String, Style)>,
    pub code: Option<String>,
    pub span: MultiSpan,
    pub children: Vec<SubDiagnostic>,
    pub suggestions: Vec<CodeSuggestion>,
}

/// For example a note attached to an error.
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct SubDiagnostic {
    pub level: Level,
    pub message: Vec<(String, Style)>,
    pub span: MultiSpan,
    pub render_span: Option<RenderSpan>,
}

#[derive(PartialEq, Eq)]
pub struct DiagnosticStyledString(pub Vec<StringPart>);

impl DiagnosticStyledString {
    pub fn new() -> DiagnosticStyledString {
        DiagnosticStyledString(vec![])
    }
    pub fn push_normal<S: Into<String>>(&mut self, t: S) {
        self.0.push(StringPart::Normal(t.into()));
    }
    pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
        self.0.push(StringPart::Highlighted(t.into()));
    }
    pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
        DiagnosticStyledString(vec![StringPart::Normal(t.into())])
    }

    pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
        DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
    }

    pub fn content(&self) -> String {
        self.0.iter().map(|x| x.content()).collect::<String>()
    }
}

#[derive(PartialEq, Eq)]
pub enum StringPart {
    Normal(String),
    Highlighted(String),
}

impl StringPart {
    pub fn content(&self) -> String {
        match self {
            &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned()
        }
    }
}

impl Diagnostic {
    pub fn new(level: Level, message: &str) -> Self {
        Diagnostic::new_with_code(level, None, message)
    }

    pub fn new_with_code(level: Level, code: Option<String>, message: &str) -> Self {
        Diagnostic {
            level,
            message: vec![(message.to_owned(), Style::NoStyle)],
            code,
            span: MultiSpan::new(),
            children: vec![],
            suggestions: vec![],
        }
    }

    /// Cancel the diagnostic (a structured diagnostic must either be emitted or
    /// canceled or it will panic when dropped).
    /// BEWARE: if this DiagnosticBuilder is an error, then creating it will
    /// bump the error count on the Handler and canceling it won't undo that.
    /// If you want to decrement the error count you should use `Handler::cancel`.
    pub fn cancel(&mut self) {
        self.level = Level::Cancelled;
    }

    pub fn cancelled(&self) -> bool {
        self.level == Level::Cancelled
    }

    /// Add a span/label to be included in the resulting snippet.
    /// This is pushed onto the `MultiSpan` that was created when the
    /// diagnostic was first built. If you don't call this function at
    /// all, and you just supplied a `Span` to create the diagnostic,
    /// then the snippet will just include that `Span`, which is
    /// called the primary span.
    pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
        self.span.push_span_label(span, label.into());
        self
    }

    pub fn note_expected_found(&mut self,
                               label: &fmt::Display,
                               expected: DiagnosticStyledString,
                               found: DiagnosticStyledString)
                               -> &mut Self
    {
        self.note_expected_found_extra(label, expected, found, &"", &"")
    }

    pub fn note_expected_found_extra(&mut self,
                                     label: &fmt::Display,
                                     expected: DiagnosticStyledString,
                                     found: DiagnosticStyledString,
                                     expected_extra: &fmt::Display,
                                     found_extra: &fmt::Display)
                                     -> &mut Self
    {
        let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
        msg.extend(expected.0.iter()
                   .map(|x| match *x {
                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
                   }));
        msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
        msg.push((format!("   found {} `", label), Style::NoStyle));
        msg.extend(found.0.iter()
                   .map(|x| match *x {
                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
                   }));
        msg.push((format!("`{}", found_extra), Style::NoStyle));

        // For now, just attach these as notes
        self.highlighted_note(msg);
        self
    }

    pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
        self.highlighted_note(vec![
            (format!("`{}` from trait: `", name), Style::NoStyle),
            (signature, Style::Highlight),
            ("`".to_string(), Style::NoStyle)]);
        self
    }

    pub fn note(&mut self, msg: &str) -> &mut Self {
        self.sub(Level::Note, msg, MultiSpan::new(), None);
        self
    }

    pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
        self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_note<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Note, msg, sp.into(), None);
        self
    }

    pub fn warn(&mut self, msg: &str) -> &mut Self {
        self.sub(Level::Warning, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_warn<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Warning, msg, sp.into(), None);
        self
    }

    pub fn help(&mut self , msg: &str) -> &mut Self {
        self.sub(Level::Help, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_help<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Help, msg, sp.into(), None);
        self
    }

    /// Prints out a message with a suggested edit of the code. If the suggestion is presented
    /// inline it will only show the text message and not the text.
    ///
    /// See `CodeSuggestion` for more information.
    pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitution_parts: vec![Substitution {
                span: sp,
                substitutions: vec![suggestion],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: false,
        });
        self
    }

    /// Prints out a message with a suggested edit of the code.
    ///
    /// In case of short messages and a simple suggestion,
    /// rustc displays it as a label like
    ///
    /// "try adding parentheses: `(tup.0).1`"
    ///
    /// The message
    ///
    /// * should not end in any punctuation (a `:` is added automatically)
    /// * should not be a question
    /// * should not contain any parts like "the following", "as shown"
    /// * may look like "to do xyz, use" or "to do xyz, use abc"
    /// * may contain a name of a function, variable or type, but not whole expressions
    ///
    /// See `CodeSuggestion` for more information.
    pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitution_parts: vec![Substitution {
                span: sp,
                substitutions: vec![suggestion],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
        });
        self
    }

    /// Prints out a message with multiple suggested edits of the code.
    pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitution_parts: vec![Substitution {
                span: sp,
                substitutions: suggestions,
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
        });
        self
    }

    pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
        self.span = sp.into();
        self
    }

    pub fn code(&mut self, s: String) -> &mut Self {
        self.code = Some(s);
        self
    }

    pub fn message(&self) -> String {
        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
    }

    pub fn styled_message(&self) -> &Vec<(String, Style)> {
        &self.message
    }

    /// Used by a lint. Copies over all details *but* the "main
    /// message".
    pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
        self.span = from.span.clone();
        self.code = from.code.clone();
        self.children.extend(from.children.iter().cloned())
    }

    /// Convenience function for internal use, clients should use one of the
    /// public methods above.
    pub(crate) fn sub(&mut self,
           level: Level,
           message: &str,
           span: MultiSpan,
           render_span: Option<RenderSpan>) {
        let sub = SubDiagnostic {
            level,
            message: vec![(message.to_owned(), Style::NoStyle)],
            span,
            render_span,
        };
        self.children.push(sub);
    }

    /// Convenience function for internal use, clients should use one of the
    /// public methods above.
    fn sub_with_highlights(&mut self,
                           level: Level,
                           message: Vec<(String, Style)>,
                           span: MultiSpan,
                           render_span: Option<RenderSpan>) {
        let sub = SubDiagnostic {
            level,
            message,
            span,
            render_span,
        };
        self.children.push(sub);
    }
}

impl SubDiagnostic {
    pub fn message(&self) -> String {
        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
    }

    pub fn styled_message(&self) -> &Vec<(String, Style)> {
        &self.message
    }
}
<|endoftext|>


<commit_before>use std::cast::transmute;
use std::libc::*;
use std::str::raw::from_buf;
use extra::term;

pub type xmlChar = c_uchar;

// These can be found in libxml/parser.h

pub static XML_SAX2_MAGIC: c_uint = 0xDEEDBEAF;

pub type internalSubsetSAXFunc          = *u8;
pub type isStandaloneSAXFunc            = *u8;
pub type hasInternalSubsetSAXFunc       = *u8;
pub type hasExternalSubsetSAXFunc       = *u8;
pub type resolveEntitySAXFunc           = *u8;
pub type getEntitySAXFunc               = *u8;
pub type entityDeclSAXFunc              = *u8;
pub type notationDeclSAXFunc            = *u8;
pub type attributeDeclSAXFunc           = *u8;
pub type elementDeclSAXFunc             = *u8;
pub type unparsedEntityDeclSAXFunc      = *u8;
pub type setDocumentLocatorSAXFunc      = *u8;
pub type startDocumentSAXFunc           = *u8;
pub type endDocumentSAXFunc             = *u8;
pub type startElementSAXFunc            = *u8;  // typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name, const xmlChar **atts);
pub type endElementSAXFunc              = *u8;  // typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name);
pub type referenceSAXFunc               = *u8;  // typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name);
pub type charactersSAXFunc              = *u8;  // typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch, int len);
pub type ignorableWhitespaceSAXFunc     = *u8;  // typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, const xmlChar *ch, int len);
pub type processingInstructionSAXFunc   = *u8;  // typedef void (*processingInstructionSAXFunc) (void *ctx, const xmlChar *target, const xmlChar *data);
pub type commentSAXFunc                 = *u8;  // typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value);
pub type warningSAXFunc                 = *u8;  // typedef void (XMLCDECL *warningSAXFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
pub type errorSAXFunc                   = *u8;  // typedef void (XMLCDECL *errorSAXFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
pub type fatalErrorSAXFunc              = *u8;  // typedef void (XMLCDECL *fatalErrorSAXFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
pub type getParameterEntitySAXFunc      = *u8;
pub type cdataBlockSAXFunc              = *u8;
pub type externalSubsetSAXFunc          = *u8;
pub type startElementNsSAX2Func         = *u8;  // typedef void (*startElementNsSAX2Func) (void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes);
pub type endElementNsSAX2Func           = *u8;  // typedef void (*endElementNsSAX2Func)   (void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI);
pub type xmlStructuredErrorFunc         = *u8;

pub struct xmlSAXHandler {
    internalSubset:         internalSubsetSAXFunc,
    isStandalone:           isStandaloneSAXFunc,
    hasInternalSubset:      hasInternalSubsetSAXFunc,
    hasExternalSubset:      hasExternalSubsetSAXFunc,
    resolveEntity:          resolveEntitySAXFunc,
    getEntity:              getEntitySAXFunc,
    entityDecl:             entityDeclSAXFunc,
    notationDecl:           notationDeclSAXFunc,
    attributeDecl:          attributeDeclSAXFunc,
    elementDecl:            elementDeclSAXFunc,
    unparsedEntityDecl:     unparsedEntityDeclSAXFunc,
    setDocumentLocator:     setDocumentLocatorSAXFunc,
    startDocument:          startDocumentSAXFunc,
    endDocument:            endDocumentSAXFunc,
    startElement:           startElementSAXFunc,
    endElement:             endElementSAXFunc,
    reference:              referenceSAXFunc,
    characters:             charactersSAXFunc,
    ignorableWhitespace:    ignorableWhitespaceSAXFunc,
    processingInstruction:  processingInstructionSAXFunc,
    comment:                commentSAXFunc,
    warning:                warningSAXFunc,
    error:                  errorSAXFunc,
    fatalError:             fatalErrorSAXFunc,
    getParameterEntity:     getParameterEntitySAXFunc,
    cdataBlock:             cdataBlockSAXFunc,
    externalSubset:         externalSubsetSAXFunc,
    initialized:            c_uint,
    _private:               *c_void,
    startElementNs:         startElementNsSAX2Func,
    endElementNs:           endElementNsSAX2Func,
    serror:                 xmlStructuredErrorFunc,
}

pub struct xmlError {
    /// What part of the library raised this error
    domain: c_int,
    /// The error code, e.g. an xmlParserError
    code: c_int,
    /// human-readable informative error messag
    message: *c_char,
    /// how consequent is the error
    level: xmlErrorLevel,
    /// the filename
    file: *c_char,
    /// the line number if available
    line: c_int,
    /// extra string information
    str1: *c_char,
    /// extra string information
    str2: *c_char,
    /// extra string information
    str3: *c_char,
    /// extra number information
    int1: c_int,
    /// column number of the error or 0 if N/A
    int2: c_int,
    /// the parser context if available
    ctxt: *c_void,
    /// the node in the tree
    node: *c_void,
}

/// Error level type alias
priv type xmlErrorLevel = c_int;

/// No error
priv static XML_ERR_NONE:    xmlErrorLevel = 0;
/// A simple warning
priv static XML_ERR_WARNING: xmlErrorLevel = 1;
/// A recoverable error
priv static XML_ERR_ERROR:   xmlErrorLevel = 2;
/// A fatal error
priv static XML_ERR_FATAL:   xmlErrorLevel = 3;

#[link_args="-lxml2"]
extern "C" {
    priv fn xmlCleanupParser();
    priv fn xmlSAXUserParseMemory(sax: *xmlSAXHandler,
                                  user_data: *c_void,
                                  buffer: *c_char,
                                  size: c_int) -> c_int;
}

pub unsafe fn parse_str<T>(sax: &xmlSAXHandler, user_data: &T, src: &str) {
    do src.as_c_str |c_str| {
        xmlSAXUserParseMemory(sax, transmute(user_data), c_str, src.len() as c_int);
        xmlCleanupParser();
    }
}

/// The severity of the error
pub enum ErrorLevel {
    /// A simple warning
    Warning,
    /// A recoverable error
    Error,
    /// A fatal error
    Fatal,
}

impl ErrorLevel {
    fn from_libxml2_constant(value: xmlErrorLevel) -> Option<ErrorLevel> {
        match value {
            XML_ERR_WARNING => Some(Warning),
            XML_ERR_ERROR   => Some(Error),
            XML_ERR_FATAL   => Some(Fatal),
            _               => None,
        }
    }

    pub fn term_color(&self) -> u8 {
        match *self {
            Warning => term::color_yellow,
            Error   => term::color_red,
            Fatal   => term::color_red,
        }
    }

    pub fn to_color_str(&self) -> ~str {
        use std::io::with_str_writer;
        do with_str_writer |writer| {
            let term = term::Terminal::new(writer);
            term.map(|t| t.fg(self.term_color()));
            writer.write_str(self.to_str());
            term.map(|t| t.fg(term::color_black));
        }
    }
}

impl ToStr for ErrorLevel {
    pub fn to_str(&self) -> ~str {
        match *self {
            Warning => ~"Warning",
            Error   => ~"Error",
            Fatal   => ~"Fatal",
        }
    }
}

/// An xml parse error
pub struct ErrorData {
    level: ErrorLevel,
    line: uint,
    column: uint,
    message: ~str,
}

impl ErrorData {
    pub unsafe fn from_ptr(error: *xmlError) -> Option<~ErrorData> {
        use std::str::raw::from_c_str;
        do ErrorLevel::from_libxml2_constant((*error).level).map |&level| {
            ~ErrorData {
                level:      level,
                message:    from_c_str((*error).message),
                line:       (*error).line as uint,
                column:     (*error).int2 as uint,
            }
        }
    }
}

impl ToStr for ErrorData {
    pub fn to_str(&self) -> ~str {
        fmt!("%?:%? %s: %s",
             self.line,
             self.column,
             self.level.to_color_str(),
             self.message)
    }
}

pub fn build_attrib_vec(atts: **xmlChar) -> ~[(~str, ~str)] {
    use std::vec;
    do vec::build |push| {
        let mut curr = atts;
        unsafe {
            while !curr.is_null() && !(*curr).is_null() {
                push((
                    from_buf(*curr),
                    from_buf(*curr.offset(1))
                ));
                curr = curr.offset(2);
            }
        }
    }
}
<commit_msg>Use new term colour constant paths<commit_after>use std::cast::transmute;
use std::libc::*;
use std::str::raw::from_buf;
use extra::term;

pub type xmlChar = c_uchar;

// These can be found in libxml/parser.h

pub static XML_SAX2_MAGIC: c_uint = 0xDEEDBEAF;

pub type internalSubsetSAXFunc          = *u8;
pub type isStandaloneSAXFunc            = *u8;
pub type hasInternalSubsetSAXFunc       = *u8;
pub type hasExternalSubsetSAXFunc       = *u8;
pub type resolveEntitySAXFunc           = *u8;
pub type getEntitySAXFunc               = *u8;
pub type entityDeclSAXFunc              = *u8;
pub type notationDeclSAXFunc            = *u8;
pub type attributeDeclSAXFunc           = *u8;
pub type elementDeclSAXFunc             = *u8;
pub type unparsedEntityDeclSAXFunc      = *u8;
pub type setDocumentLocatorSAXFunc      = *u8;
pub type startDocumentSAXFunc           = *u8;
pub type endDocumentSAXFunc             = *u8;
pub type startElementSAXFunc            = *u8;  // typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name, const xmlChar **atts);
pub type endElementSAXFunc              = *u8;  // typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name);
pub type referenceSAXFunc               = *u8;  // typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name);
pub type charactersSAXFunc              = *u8;  // typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch, int len);
pub type ignorableWhitespaceSAXFunc     = *u8;  // typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, const xmlChar *ch, int len);
pub type processingInstructionSAXFunc   = *u8;  // typedef void (*processingInstructionSAXFunc) (void *ctx, const xmlChar *target, const xmlChar *data);
pub type commentSAXFunc                 = *u8;  // typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value);
pub type warningSAXFunc                 = *u8;  // typedef void (XMLCDECL *warningSAXFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
pub type errorSAXFunc                   = *u8;  // typedef void (XMLCDECL *errorSAXFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
pub type fatalErrorSAXFunc              = *u8;  // typedef void (XMLCDECL *fatalErrorSAXFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
pub type getParameterEntitySAXFunc      = *u8;
pub type cdataBlockSAXFunc              = *u8;
pub type externalSubsetSAXFunc          = *u8;
pub type startElementNsSAX2Func         = *u8;  // typedef void (*startElementNsSAX2Func) (void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes);
pub type endElementNsSAX2Func           = *u8;  // typedef void (*endElementNsSAX2Func)   (void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI);
pub type xmlStructuredErrorFunc         = *u8;

pub struct xmlSAXHandler {
    internalSubset:         internalSubsetSAXFunc,
    isStandalone:           isStandaloneSAXFunc,
    hasInternalSubset:      hasInternalSubsetSAXFunc,
    hasExternalSubset:      hasExternalSubsetSAXFunc,
    resolveEntity:          resolveEntitySAXFunc,
    getEntity:              getEntitySAXFunc,
    entityDecl:             entityDeclSAXFunc,
    notationDecl:           notationDeclSAXFunc,
    attributeDecl:          attributeDeclSAXFunc,
    elementDecl:            elementDeclSAXFunc,
    unparsedEntityDecl:     unparsedEntityDeclSAXFunc,
    setDocumentLocator:     setDocumentLocatorSAXFunc,
    startDocument:          startDocumentSAXFunc,
    endDocument:            endDocumentSAXFunc,
    startElement:           startElementSAXFunc,
    endElement:             endElementSAXFunc,
    reference:              referenceSAXFunc,
    characters:             charactersSAXFunc,
    ignorableWhitespace:    ignorableWhitespaceSAXFunc,
    processingInstruction:  processingInstructionSAXFunc,
    comment:                commentSAXFunc,
    warning:                warningSAXFunc,
    error:                  errorSAXFunc,
    fatalError:             fatalErrorSAXFunc,
    getParameterEntity:     getParameterEntitySAXFunc,
    cdataBlock:             cdataBlockSAXFunc,
    externalSubset:         externalSubsetSAXFunc,
    initialized:            c_uint,
    _private:               *c_void,
    startElementNs:         startElementNsSAX2Func,
    endElementNs:           endElementNsSAX2Func,
    serror:                 xmlStructuredErrorFunc,
}

pub struct xmlError {
    /// What part of the library raised this error
    domain: c_int,
    /// The error code, e.g. an xmlParserError
    code: c_int,
    /// human-readable informative error messag
    message: *c_char,
    /// how consequent is the error
    level: xmlErrorLevel,
    /// the filename
    file: *c_char,
    /// the line number if available
    line: c_int,
    /// extra string information
    str1: *c_char,
    /// extra string information
    str2: *c_char,
    /// extra string information
    str3: *c_char,
    /// extra number information
    int1: c_int,
    /// column number of the error or 0 if N/A
    int2: c_int,
    /// the parser context if available
    ctxt: *c_void,
    /// the node in the tree
    node: *c_void,
}

/// Error level type alias
priv type xmlErrorLevel = c_int;

/// No error
priv static XML_ERR_NONE:    xmlErrorLevel = 0;
/// A simple warning
priv static XML_ERR_WARNING: xmlErrorLevel = 1;
/// A recoverable error
priv static XML_ERR_ERROR:   xmlErrorLevel = 2;
/// A fatal error
priv static XML_ERR_FATAL:   xmlErrorLevel = 3;

#[link_args="-lxml2"]
extern "C" {
    priv fn xmlCleanupParser();
    priv fn xmlSAXUserParseMemory(sax: *xmlSAXHandler,
                                  user_data: *c_void,
                                  buffer: *c_char,
                                  size: c_int) -> c_int;
}

pub unsafe fn parse_str<T>(sax: &xmlSAXHandler, user_data: &T, src: &str) {
    do src.as_c_str |c_str| {
        xmlSAXUserParseMemory(sax, transmute(user_data), c_str, src.len() as c_int);
        xmlCleanupParser();
    }
}

/// The severity of the error
pub enum ErrorLevel {
    /// A simple warning
    Warning,
    /// A recoverable error
    Error,
    /// A fatal error
    Fatal,
}

impl ErrorLevel {
    fn from_libxml2_constant(value: xmlErrorLevel) -> Option<ErrorLevel> {
        match value {
            XML_ERR_WARNING => Some(Warning),
            XML_ERR_ERROR   => Some(Error),
            XML_ERR_FATAL   => Some(Fatal),
            _               => None,
        }
    }

    pub fn term_color(&self) -> u16 {
        match *self {
            Warning => term::color::yellow,
            Error   => term::color::red,
            Fatal   => term::color::red,
        }
    }

    pub fn to_color_str(&self) -> ~str {
        use std::io::with_str_writer;
        do with_str_writer |writer| {
            let term = term::Terminal::new(writer);
            term.map(|t| t.fg(self.term_color()));
            writer.write_str(self.to_str());
            term.map(|t| t.fg(term::color::black));
        }
    }
}

impl ToStr for ErrorLevel {
    pub fn to_str(&self) -> ~str {
        match *self {
            Warning => ~"Warning",
            Error   => ~"Error",
            Fatal   => ~"Fatal",
        }
    }
}

/// An xml parse error
pub struct ErrorData {
    level: ErrorLevel,
    line: uint,
    column: uint,
    message: ~str,
}

impl ErrorData {
    pub unsafe fn from_ptr(error: *xmlError) -> Option<~ErrorData> {
        use std::str::raw::from_c_str;
        do ErrorLevel::from_libxml2_constant((*error).level).map |&level| {
            ~ErrorData {
                level:      level,
                message:    from_c_str((*error).message),
                line:       (*error).line as uint,
                column:     (*error).int2 as uint,
            }
        }
    }
}

impl ToStr for ErrorData {
    pub fn to_str(&self) -> ~str {
        fmt!("%?:%? %s: %s",
             self.line,
             self.column,
             self.level.to_color_str(),
             self.message)
    }
}

pub fn build_attrib_vec(atts: **xmlChar) -> ~[(~str, ~str)] {
    use std::vec;
    do vec::build |push| {
        let mut curr = atts;
        unsafe {
            while !curr.is_null() && !(*curr).is_null() {
                push((
                    from_buf(*curr),
                    from_buf(*curr.offset(1))
                ));
                curr = curr.offset(2);
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(flt2dec)]
#![feature(test)]

extern crate test;

mod any;
mod ascii;
mod char;
mod fmt;
mod hash;
mod iter;
mod num;
mod ops;
mod pattern;
mod slice;
<commit_msg>Disable core benches on wasm (benches not supported).<commit_after>// wasm32 does not support benches (no time).
#![cfg(not(target_arch = "wasm32"))]
#![feature(flt2dec)]
#![feature(test)]

extern crate test;

mod any;
mod ascii;
mod char;
mod fmt;
mod hash;
mod iter;
mod num;
mod ops;
mod pattern;
mod slice;
<|endoftext|>


<commit_before>use crate::ty;
use crate::ty::TyCtxt;
use crate::hir::map::definitions::FIRST_FREE_HIGH_DEF_INDEX;
use rustc_data_structures::indexed_vec::Idx;
use serialize;
use std::fmt;
use std::u32;

newtype_index! {
    pub struct CrateId {
        ENCODABLE = custom
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CrateNum {
    /// Virtual crate for builtin macros
    // FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
    // `CrateNum`s.
    BuiltinMacros,
    /// A special CrateNum that we use for the tcx.rcache when decoding from
    /// the incr. comp. cache.
    ReservedForIncrCompCache,
    Index(CrateId),
}

impl ::std::fmt::Debug for CrateNum {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        match self {
            CrateNum::Index(id) => write!(fmt, "crate{}", id.private),
            CrateNum::BuiltinMacros => write!(fmt, "builtin macros crate"),
            CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"),
        }
    }
}

/// Item definitions in the currently-compiled crate would have the CrateNum
/// LOCAL_CRATE in their DefId.
pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32_const(0));

impl Idx for CrateNum {
    #[inline]
    fn new(value: usize) -> Self {
        CrateNum::Index(Idx::new(value))
    }

    #[inline]
    fn index(self) -> usize {
        match self {
            CrateNum::Index(idx) => Idx::index(idx),
            _ => bug!("Tried to get crate index of {:?}", self),
        }
    }
}

impl CrateNum {
    pub fn new(x: usize) -> CrateNum {
        CrateNum::from_usize(x)
    }

    pub fn from_usize(x: usize) -> CrateNum {
        CrateNum::Index(CrateId::from_usize(x))
    }

    pub fn from_u32(x: u32) -> CrateNum {
        CrateNum::Index(CrateId::from_u32(x))
    }

    pub fn as_usize(self) -> usize {
        match self {
            CrateNum::Index(id) => id.as_usize(),
            _ => bug!("tried to get index of nonstandard crate {:?}", self),
        }
    }

    pub fn as_u32(self) -> u32 {
        match self {
            CrateNum::Index(id) => id.as_u32(),
            _ => bug!("tried to get index of nonstandard crate {:?}", self),
        }
    }

    pub fn as_def_id(&self) -> DefId { DefId { krate: *self, index: CRATE_DEF_INDEX } }
}

impl fmt::Display for CrateNum {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            CrateNum::Index(id) => fmt::Display::fmt(&id.private, f),
            CrateNum::BuiltinMacros => write!(f, "builtin macros crate"),
            CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"),
        }
    }
}

impl serialize::UseSpecializedEncodable for CrateNum {}
impl serialize::UseSpecializedDecodable for CrateNum {}

/// A DefIndex is an index into the hir-map for a crate, identifying a
/// particular definition. It should really be considered an interned
/// shorthand for a particular DefPath.
///
/// At the moment we are allocating the numerical values of DefIndexes from two
/// address spaces: DefIndexAddressSpace::Low and DefIndexAddressSpace::High.
/// This allows us to allocate the DefIndexes of all item-likes
/// (Items, TraitItems, and ImplItems) into one of these spaces and
/// consequently use a simple array for lookup tables keyed by DefIndex and
/// known to be densely populated. This is especially important for the HIR map.
///
/// Since the DefIndex is mostly treated as an opaque ID, you probably
/// don't have to care about these address spaces.

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

/// The crate root is always assigned index 0 by the AST Map code,
/// thanks to `NodeCollector::new`.
pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);

impl fmt::Debug for DefIndex {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f,
               "DefIndex({}:{})",
               self.address_space().index(),
               self.as_array_index())
    }
}

impl DefIndex {
    #[inline]
    pub fn address_space(&self) -> DefIndexAddressSpace {
        match self.0 & 1 {
            0 => DefIndexAddressSpace::Low,
            1 => DefIndexAddressSpace::High,
            _ => unreachable!()
        }
    }

    /// Converts this DefIndex into a zero-based array index.
    /// This index is the offset within the given DefIndexAddressSpace.
    #[inline]
    pub fn as_array_index(&self) -> usize {
        (self.0 >> 1) as usize
    }

    #[inline]
    pub fn from_array_index(i: usize, address_space: DefIndexAddressSpace) -> DefIndex {
        DefIndex::from_raw_u32(((i << 1) | (address_space as usize)) as u32)
    }

    // Proc macros from a proc-macro crate have a kind of virtual DefIndex. This
    // function maps the index of the macro within the crate (which is also the
    // index of the macro in the CrateMetadata::proc_macros array) to the
    // corresponding DefIndex.
    pub fn from_proc_macro_index(proc_macro_index: usize) -> DefIndex {
        // DefIndex for proc macros start from FIRST_FREE_HIGH_DEF_INDEX,
        // because the first FIRST_FREE_HIGH_DEF_INDEX indexes are reserved
        // for internal use.
        let def_index = DefIndex::from_array_index(
            proc_macro_index.checked_add(FIRST_FREE_HIGH_DEF_INDEX)
                .expect("integer overflow adding `proc_macro_index`"),
            DefIndexAddressSpace::High);
        assert!(def_index != CRATE_DEF_INDEX);
        def_index
    }

    // This function is the reverse of from_proc_macro_index() above.
    pub fn to_proc_macro_index(self: DefIndex) -> usize {
        assert_eq!(self.address_space(), DefIndexAddressSpace::High);

        self.as_array_index().checked_sub(FIRST_FREE_HIGH_DEF_INDEX)
            .unwrap_or_else(|| {
                bug!("using local index {:?} as proc-macro index", self)
            })
    }

    // Don't use this if you don't know about the DefIndex encoding.
    pub fn from_raw_u32(x: u32) -> DefIndex {
        DefIndex(x)
    }

    // Don't use this if you don't know about the DefIndex encoding.
    pub fn as_raw_u32(&self) -> u32 {
        self.0
    }
}

impl serialize::UseSpecializedEncodable for DefIndex {}
impl serialize::UseSpecializedDecodable for DefIndex {}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum DefIndexAddressSpace {
    Low = 0,
    High = 1,
}

impl DefIndexAddressSpace {
    #[inline]
    pub fn index(&self) -> usize {
        *self as usize
    }
}

/// A `DefId` identifies a particular *definition*, by combining a crate
/// index and a def index.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
pub struct DefId {
    pub krate: CrateNum,
    pub index: DefIndex,
}

impl fmt::Debug for DefId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "DefId({}/{}:{}",
               self.krate,
               self.index.address_space().index(),
               self.index.as_array_index())?;

        ty::tls::with_opt(|opt_tcx| {
            if let Some(tcx) = opt_tcx {
                write!(f, " ~ {}", tcx.def_path_debug_str(*self))?;
            }
            Ok(())
        })?;

        write!(f, ")")
    }
}

impl DefId {
    /// Makes a local `DefId` from the given `DefIndex`.
    #[inline]
    pub fn local(index: DefIndex) -> DefId {
        DefId { krate: LOCAL_CRATE, index: index }
    }

    #[inline]
    pub fn is_local(self) -> bool {
        self.krate == LOCAL_CRATE
    }

    #[inline]
    pub fn to_local(self) -> LocalDefId {
        LocalDefId::from_def_id(self)
    }

    pub fn describe_as_module(&self, tcx: TyCtxt<'_, '_, '_>) -> String {
        if self.is_local() && self.index == CRATE_DEF_INDEX {
            format!("top-level module")
        } else {
            format!("module `{}`", tcx.def_path_str(*self))
        }
    }
}

impl serialize::UseSpecializedEncodable for DefId {}
impl serialize::UseSpecializedDecodable for DefId {}

/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
/// we encode this information in the type, we can ensure at compile time that
/// no DefIds from upstream crates get thrown into the mix. There are quite a
/// few cases where we know that only DefIds from the local crate are expected
/// and a DefId from a different crate would signify a bug somewhere. This
/// is when LocalDefId comes in handy.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct LocalDefId(DefIndex);

impl LocalDefId {
    #[inline]
    pub fn from_def_id(def_id: DefId) -> LocalDefId {
        assert!(def_id.is_local());
        LocalDefId(def_id.index)
    }

    #[inline]
    pub fn to_def_id(self) -> DefId {
        DefId {
            krate: LOCAL_CRATE,
            index: self.0
        }
    }
}

impl fmt::Debug for LocalDefId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.to_def_id().fmt(f)
    }
}

impl serialize::UseSpecializedEncodable for LocalDefId {}
impl serialize::UseSpecializedDecodable for LocalDefId {}
<commit_msg>Uplift match_def_path from Clippy<commit_after>use crate::ty::{self, print::Printer, subst::Kind, Ty, TyCtxt};
use crate::hir::map::definitions::{DisambiguatedDefPathData, FIRST_FREE_HIGH_DEF_INDEX};
use rustc_data_structures::indexed_vec::Idx;
use serialize;
use std::fmt;
use std::u32;
use syntax::symbol::{LocalInternedString, Symbol};

newtype_index! {
    pub struct CrateId {
        ENCODABLE = custom
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CrateNum {
    /// Virtual crate for builtin macros
    // FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
    // `CrateNum`s.
    BuiltinMacros,
    /// A special CrateNum that we use for the tcx.rcache when decoding from
    /// the incr. comp. cache.
    ReservedForIncrCompCache,
    Index(CrateId),
}

impl ::std::fmt::Debug for CrateNum {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        match self {
            CrateNum::Index(id) => write!(fmt, "crate{}", id.private),
            CrateNum::BuiltinMacros => write!(fmt, "builtin macros crate"),
            CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"),
        }
    }
}

/// Item definitions in the currently-compiled crate would have the CrateNum
/// LOCAL_CRATE in their DefId.
pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32_const(0));

impl Idx for CrateNum {
    #[inline]
    fn new(value: usize) -> Self {
        CrateNum::Index(Idx::new(value))
    }

    #[inline]
    fn index(self) -> usize {
        match self {
            CrateNum::Index(idx) => Idx::index(idx),
            _ => bug!("Tried to get crate index of {:?}", self),
        }
    }
}

impl CrateNum {
    pub fn new(x: usize) -> CrateNum {
        CrateNum::from_usize(x)
    }

    pub fn from_usize(x: usize) -> CrateNum {
        CrateNum::Index(CrateId::from_usize(x))
    }

    pub fn from_u32(x: u32) -> CrateNum {
        CrateNum::Index(CrateId::from_u32(x))
    }

    pub fn as_usize(self) -> usize {
        match self {
            CrateNum::Index(id) => id.as_usize(),
            _ => bug!("tried to get index of nonstandard crate {:?}", self),
        }
    }

    pub fn as_u32(self) -> u32 {
        match self {
            CrateNum::Index(id) => id.as_u32(),
            _ => bug!("tried to get index of nonstandard crate {:?}", self),
        }
    }

    pub fn as_def_id(&self) -> DefId { DefId { krate: *self, index: CRATE_DEF_INDEX } }
}

impl fmt::Display for CrateNum {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            CrateNum::Index(id) => fmt::Display::fmt(&id.private, f),
            CrateNum::BuiltinMacros => write!(f, "builtin macros crate"),
            CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"),
        }
    }
}

impl serialize::UseSpecializedEncodable for CrateNum {}
impl serialize::UseSpecializedDecodable for CrateNum {}

/// A DefIndex is an index into the hir-map for a crate, identifying a
/// particular definition. It should really be considered an interned
/// shorthand for a particular DefPath.
///
/// At the moment we are allocating the numerical values of DefIndexes from two
/// address spaces: DefIndexAddressSpace::Low and DefIndexAddressSpace::High.
/// This allows us to allocate the DefIndexes of all item-likes
/// (Items, TraitItems, and ImplItems) into one of these spaces and
/// consequently use a simple array for lookup tables keyed by DefIndex and
/// known to be densely populated. This is especially important for the HIR map.
///
/// Since the DefIndex is mostly treated as an opaque ID, you probably
/// don't have to care about these address spaces.

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

/// The crate root is always assigned index 0 by the AST Map code,
/// thanks to `NodeCollector::new`.
pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);

impl fmt::Debug for DefIndex {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f,
               "DefIndex({}:{})",
               self.address_space().index(),
               self.as_array_index())
    }
}

impl DefIndex {
    #[inline]
    pub fn address_space(&self) -> DefIndexAddressSpace {
        match self.0 & 1 {
            0 => DefIndexAddressSpace::Low,
            1 => DefIndexAddressSpace::High,
            _ => unreachable!()
        }
    }

    /// Converts this DefIndex into a zero-based array index.
    /// This index is the offset within the given DefIndexAddressSpace.
    #[inline]
    pub fn as_array_index(&self) -> usize {
        (self.0 >> 1) as usize
    }

    #[inline]
    pub fn from_array_index(i: usize, address_space: DefIndexAddressSpace) -> DefIndex {
        DefIndex::from_raw_u32(((i << 1) | (address_space as usize)) as u32)
    }

    // Proc macros from a proc-macro crate have a kind of virtual DefIndex. This
    // function maps the index of the macro within the crate (which is also the
    // index of the macro in the CrateMetadata::proc_macros array) to the
    // corresponding DefIndex.
    pub fn from_proc_macro_index(proc_macro_index: usize) -> DefIndex {
        // DefIndex for proc macros start from FIRST_FREE_HIGH_DEF_INDEX,
        // because the first FIRST_FREE_HIGH_DEF_INDEX indexes are reserved
        // for internal use.
        let def_index = DefIndex::from_array_index(
            proc_macro_index.checked_add(FIRST_FREE_HIGH_DEF_INDEX)
                .expect("integer overflow adding `proc_macro_index`"),
            DefIndexAddressSpace::High);
        assert!(def_index != CRATE_DEF_INDEX);
        def_index
    }

    // This function is the reverse of from_proc_macro_index() above.
    pub fn to_proc_macro_index(self: DefIndex) -> usize {
        assert_eq!(self.address_space(), DefIndexAddressSpace::High);

        self.as_array_index().checked_sub(FIRST_FREE_HIGH_DEF_INDEX)
            .unwrap_or_else(|| {
                bug!("using local index {:?} as proc-macro index", self)
            })
    }

    // Don't use this if you don't know about the DefIndex encoding.
    pub fn from_raw_u32(x: u32) -> DefIndex {
        DefIndex(x)
    }

    // Don't use this if you don't know about the DefIndex encoding.
    pub fn as_raw_u32(&self) -> u32 {
        self.0
    }
}

impl serialize::UseSpecializedEncodable for DefIndex {}
impl serialize::UseSpecializedDecodable for DefIndex {}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum DefIndexAddressSpace {
    Low = 0,
    High = 1,
}

impl DefIndexAddressSpace {
    #[inline]
    pub fn index(&self) -> usize {
        *self as usize
    }
}

/// A `DefId` identifies a particular *definition*, by combining a crate
/// index and a def index.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
pub struct DefId {
    pub krate: CrateNum,
    pub index: DefIndex,
}

impl fmt::Debug for DefId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "DefId({}/{}:{}",
               self.krate,
               self.index.address_space().index(),
               self.index.as_array_index())?;

        ty::tls::with_opt(|opt_tcx| {
            if let Some(tcx) = opt_tcx {
                write!(f, " ~ {}", tcx.def_path_debug_str(*self))?;
            }
            Ok(())
        })?;

        write!(f, ")")
    }
}

impl DefId {
    /// Makes a local `DefId` from the given `DefIndex`.
    #[inline]
    pub fn local(index: DefIndex) -> DefId {
        DefId { krate: LOCAL_CRATE, index: index }
    }

    #[inline]
    pub fn is_local(self) -> bool {
        self.krate == LOCAL_CRATE
    }

    #[inline]
    pub fn to_local(self) -> LocalDefId {
        LocalDefId::from_def_id(self)
    }

    pub fn describe_as_module(&self, tcx: TyCtxt<'_, '_, '_>) -> String {
        if self.is_local() && self.index == CRATE_DEF_INDEX {
            format!("top-level module")
        } else {
            format!("module `{}`", tcx.def_path_str(*self))
        }
    }

    /// Check if a `DefId`'s path matches the given absolute type path usage.
    // Uplifted from rust-lang/rust-clippy
    pub fn match_path<'a, 'tcx>(self, tcx: TyCtxt<'a, 'tcx, 'tcx>, path: &[&str]) -> bool {
        pub struct AbsolutePathPrinter<'a, 'tcx> {
            pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
        }

        impl<'tcx> Printer<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> {
            type Error = !;

            type Path = Vec<LocalInternedString>;
            type Region = ();
            type Type = ();
            type DynExistential = ();

            fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
                self.tcx
            }

            fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
                Ok(())
            }

            fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
                Ok(())
            }

            fn print_dyn_existential(
                self,
                _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
                ) -> Result<Self::DynExistential, Self::Error> {
                Ok(())
            }

            fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
                Ok(vec![self.tcx.original_crate_name(cnum).as_str()])
            }

            fn path_qualified(
                self,
                self_ty: Ty<'tcx>,
                trait_ref: Option<ty::TraitRef<'tcx>>,
                ) -> Result<Self::Path, Self::Error> {
                if trait_ref.is_none() {
                    if let ty::Adt(def, substs) = self_ty.sty {
                        return self.print_def_path(def.did, substs);
                    }
                }

                // This shouldn't ever be needed, but just in case:
                Ok(vec![match trait_ref {
                    Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)).as_str(),
                    None => Symbol::intern(&format!("<{}>", self_ty)).as_str(),
                }])
            }

            fn path_append_impl(
                self,
                print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
                _disambiguated_data: &DisambiguatedDefPathData,
                self_ty: Ty<'tcx>,
                trait_ref: Option<ty::TraitRef<'tcx>>,
                ) -> Result<Self::Path, Self::Error> {
                let mut path = print_prefix(self)?;

                // This shouldn't ever be needed, but just in case:
                path.push(match trait_ref {
                    Some(trait_ref) => {
                        Symbol::intern(&format!("<impl {} for {}>", trait_ref, self_ty)).as_str()
                    },
                    None => Symbol::intern(&format!("<impl {}>", self_ty)).as_str(),
                });

                Ok(path)
            }

            fn path_append(
                self,
                print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
                disambiguated_data: &DisambiguatedDefPathData,
                ) -> Result<Self::Path, Self::Error> {
                let mut path = print_prefix(self)?;
                path.push(disambiguated_data.data.as_interned_str().as_str());
                Ok(path)
            }

            fn path_generic_args(
                self,
                print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
                _args: &[Kind<'tcx>],
                ) -> Result<Self::Path, Self::Error> {
                print_prefix(self)
            }
        }

        let names = AbsolutePathPrinter { tcx }.print_def_path(self, &[]).unwrap();

        names.len() == path.len()
            && names.into_iter().zip(path.iter()).all(|(a, &b)| *a == *b)
    }
}

impl serialize::UseSpecializedEncodable for DefId {}
impl serialize::UseSpecializedDecodable for DefId {}

/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
/// we encode this information in the type, we can ensure at compile time that
/// no DefIds from upstream crates get thrown into the mix. There are quite a
/// few cases where we know that only DefIds from the local crate are expected
/// and a DefId from a different crate would signify a bug somewhere. This
/// is when LocalDefId comes in handy.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct LocalDefId(DefIndex);

impl LocalDefId {
    #[inline]
    pub fn from_def_id(def_id: DefId) -> LocalDefId {
        assert!(def_id.is_local());
        LocalDefId(def_id.index)
    }

    #[inline]
    pub fn to_def_id(self) -> DefId {
        DefId {
            krate: LOCAL_CRATE,
            index: self.0
        }
    }
}

impl fmt::Debug for LocalDefId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.to_def_id().fmt(f)
    }
}

impl serialize::UseSpecializedEncodable for LocalDefId {}
impl serialize::UseSpecializedDecodable for LocalDefId {}
<|endoftext|>


<commit_before>use num::Complex;

fn next_value(previous: f64, point: Complex) -> f64 {
    let z = previous * previous;
    let result = z + point.abs();
    return result;
}

#[test]
fn nex_value_of_null() {
    let previous = 0.0;
    let point = Complex::new(0.0,0.0);

    assert_eq!(0.0, next_value(previous,point));
}

<commit_msg>Made a few test and bounded stuff<commit_after>use num::Complex;

struct Pixel {
    point: Complex,
    iter: i32,
}

fn next_value(previous: f64, point: &Complex) -> f64 {
    let z = previous * previous;
    let result = z + point.abs();
    return result;
}

fn bounded(point: Complex) -> i32 {
    let mut c = 0.0;
    let mut i = 0;
    let point = point;

    while c <= 1000.0 && i <= 20 {
        i += 1;
        c = next_value(c, &point);
    }

    if c > 1000.0 {
        return i;
    } else {
        return -1;
    }
}

#[test]
fn nex_value_of_null() {
    let previous = 0.0;
    let point = Complex::new(0.0,0.0);

    assert_eq!(0.0, next_value(previous,&point));
}

#[test]
fn zero_is_bounded() {
    let point = Complex::new(0.0,0.0);

    assert_eq!(-1,bounded(point));
}

#[test]
fn unbound_is_unbound() {
    let point = Complex::new(-1.0,1.0);

    assert!(bounded(point) != -1);
}
<|endoftext|>