<commit_before>use std::cell::Cell;

use nom::branch::alt;
use nom::bytes::complete::{tag, take_while1};
use nom::combinator::map_res;
use nom::multi::separated_list;
use nom::IResult;

use crate::services::server_lists::{OpenNic, PublicDns, IPV};

use super::*;

pub(crate) fn parse_server_list_spec<'a>(input: &'a str) -> IResult<&'a str, ServerListSpec> {
    let (input, spec) = alt((public_dns, opennic))(input)?;

    Ok((input, spec))
}

fn public_dns<'a>(input: &'a str) -> IResult<&'a str, ServerListSpec> {
    let (input, _) = tag("public-dns")(input)?;
    let (input, spec) = public_dns_spec(input)?;
    Ok((input, ServerListSpec::PublicDns { spec }))
}

fn public_dns_spec<'a>(input: &'a str) -> IResult<&'a str, PublicDns> {
    if input.is_empty() {
        Ok((input, Default::default()))
    } else {
        let (input, _) = tag(":")(input)?;
        let (input, country) = take_while1(|c: char| c.is_alphanumeric())(input)?;
        Ok((
            input,
            PublicDns {
                country: Some(country.to_string()),
            },
        ))
    }
}

fn opennic<'a>(input: &'a str) -> IResult<&'a str, ServerListSpec> {
    let (input, _) = tag("opennic")(input)?;
    let (input, spec) = opennic_spec(input)?;
    Ok((input, ServerListSpec::OpenNic { spec }))
}

fn opennic_spec<'a>(input: &'a str) -> IResult<&'a str, OpenNic> {
    if input.is_empty() {
        Ok((input, Default::default()))
    } else {
        let (input, spec) = opennic_spec_params(input)?;
        Ok((input, spec))
    }
}

fn opennic_spec_params<'a>(input: &'a str) -> IResult<&'a str, OpenNic> {
    let (input, _) = tag(":")(input)?;
    let spec = Cell::new(OpenNic::default());
    let (input, _) = separated_list(
        tag(","),
        alt((
            |x| opennic_spec_params_anon(&spec, x),
            |x| opennic_spec_params_number(&spec, x),
            |x| opennic_spec_params_reliability(&spec, x),
            |x| opennic_spec_params_ipv(&spec, x),
        )),
    )(input)?;

    Ok((input, spec.into_inner()))
}

fn opennic_spec_params_anon<'a>(cell: &Cell<OpenNic>, input: &'a str) -> IResult<&'a str, ()> {
    let (input, _) = tag("anon")(input)?;
    let mut spec = cell.take();
    spec.anon = true;
    cell.set(spec);

    Ok((input, ()))
}

fn opennic_spec_params_number<'a>(cell: &Cell<OpenNic>, input: &'a str) -> IResult<&'a str, ()> {
    let (input, _) = tag("number=")(input)?;
    let (input, number) = map_res(take_while1(|c: char| c.is_digit(10) || c == '.'), usize::from_str)(input)?;
    let mut spec = cell.take();
    spec.number = number;
    cell.set(spec);

    Ok((input, ()))
}

fn opennic_spec_params_reliability<'a>(cell: &Cell<OpenNic>, input: &'a str) -> IResult<&'a str, ()> {
    let (input, _) = tag("reliability=")(input)?;
    let (input, reliability) = map_res(take_while1(|c: char| c.is_digit(10) || c == '.'), usize::from_str)(input)?;
    let mut spec = cell.take();
    spec.reliability = reliability;
    cell.set(spec);

    Ok((input, ()))
}

fn opennic_spec_params_ipv<'a>(cell: &Cell<OpenNic>, input: &'a str) -> IResult<&'a str, ()> {
    let (input, _) = tag("ipv=")(input)?;
    let (input, ipv) = map_res(take_while1(|c: char| c.is_digit(10) || c == '.'), IPV::from_str)(input)?;
    let mut spec = cell.take();
    spec.ipv = ipv;
    cell.set(spec);

    Ok((input, ()))
}

#[cfg(test)]
mod tests {
    use spectral::prelude::*;

    use crate::services::server_lists::PublicDns;

    use super::*;

    #[test]
    fn public_dns_default() {
        crate::utils::tests::logging::init();
        let str = "public-dns";
        let expected = ServerListSpec::PublicDns {
            spec: Default::default(),
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn public_country() {
        crate::utils::tests::logging::init();
        let str = "public-dns:de";
        let expected = ServerListSpec::PublicDns {
            spec: PublicDns {
                country: Some("de".to_string()),
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn public_separator_missing_country() {
        crate::utils::tests::logging::init();
        let str = "public-dns:";

        let res = parse_server_list_spec(&str);

        assert_that(&res).is_err();
    }

    #[test]
    fn opennic_default() {
        crate::utils::tests::logging::init();
        let str = "opennic";
        let expected = ServerListSpec::OpenNic {
            spec: Default::default(),
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
        assert_that(&config.opennic())
            .is_some()
            .map(|x| &x.anon)
            .is_equal_to(false);
    }

    #[test]
    fn opennic_anon() {
        crate::utils::tests::logging::init();
        let str = "opennic:anon";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                anon: true,
                ..Default::default()
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
        assert_that(&config.opennic())
            .is_some()
            .map(|x| &x.anon)
            .is_equal_to(true);
    }

    #[test]
    fn opennic_number() {
        crate::utils::tests::logging::init();
        let str = "opennic:number=100";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                number: 100,
                ..Default::default()
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn opennic_reliability() {
        crate::utils::tests::logging::init();
        let str = "opennic:reliability=40";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                reliability: 40,
                ..Default::default()
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn opennic_ipv4() {
        crate::utils::tests::logging::init();
        let str = "opennic:ipv=4";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                ipv: IPV::V4,
                ..Default::default()
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn opennic_all() {
        crate::utils::tests::logging::init();
        let str = "opennic:anon,number=100,reliability=50,ipv=6";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                anon: true,
                number: 100,
                reliability: 50,
                ipv: IPV::V6,
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }
}
<commit_msg>Clippify<commit_after>use std::cell::Cell;

use nom::branch::alt;
use nom::bytes::complete::{tag, take_while1};
use nom::combinator::map_res;
use nom::multi::separated_list;
use nom::IResult;

use crate::services::server_lists::{OpenNic, PublicDns, IPV};

use super::*;

pub(crate) fn parse_server_list_spec(input: &str) -> IResult<&str, ServerListSpec> {
    let (input, spec) = alt((public_dns, opennic))(input)?;

    Ok((input, spec))
}

fn public_dns(input: &str) -> IResult<&str, ServerListSpec> {
    let (input, _) = tag("public-dns")(input)?;
    let (input, spec) = public_dns_spec(input)?;
    Ok((input, ServerListSpec::PublicDns { spec }))
}

fn public_dns_spec(input: &str) -> IResult<&str, PublicDns> {
    if input.is_empty() {
        Ok((input, Default::default()))
    } else {
        let (input, _) = tag(":")(input)?;
        let (input, country) = take_while1(|c: char| c.is_alphanumeric())(input)?;
        Ok((
            input,
            PublicDns {
                country: Some(country.to_string()),
            },
        ))
    }
}

fn opennic(input: &str) -> IResult<&str, ServerListSpec> {
    let (input, _) = tag("opennic")(input)?;
    let (input, spec) = opennic_spec(input)?;
    Ok((input, ServerListSpec::OpenNic { spec }))
}

fn opennic_spec(input: &str) -> IResult<&str, OpenNic> {
    if input.is_empty() {
        Ok((input, Default::default()))
    } else {
        let (input, spec) = opennic_spec_params(input)?;
        Ok((input, spec))
    }
}

fn opennic_spec_params(input: &str) -> IResult<&str, OpenNic> {
    let (input, _) = tag(":")(input)?;
    let spec = Cell::new(OpenNic::default());
    let (input, _) = separated_list(
        tag(","),
        alt((
            |x| opennic_spec_params_anon(&spec, x),
            |x| opennic_spec_params_number(&spec, x),
            |x| opennic_spec_params_reliability(&spec, x),
            |x| opennic_spec_params_ipv(&spec, x),
        )),
    )(input)?;

    Ok((input, spec.into_inner()))
}

fn opennic_spec_params_anon<'a>(cell: &Cell<OpenNic>, input: &'a str) -> IResult<&'a str, ()> {
    let (input, _) = tag("anon")(input)?;
    let mut spec = cell.take();
    spec.anon = true;
    cell.set(spec);

    Ok((input, ()))
}

fn opennic_spec_params_number<'a>(cell: &Cell<OpenNic>, input: &'a str) -> IResult<&'a str, ()> {
    let (input, _) = tag("number=")(input)?;
    let (input, number) = map_res(take_while1(|c: char| c.is_digit(10) || c == '.'), usize::from_str)(input)?;
    let mut spec = cell.take();
    spec.number = number;
    cell.set(spec);

    Ok((input, ()))
}

fn opennic_spec_params_reliability<'a>(cell: &Cell<OpenNic>, input: &'a str) -> IResult<&'a str, ()> {
    let (input, _) = tag("reliability=")(input)?;
    let (input, reliability) = map_res(take_while1(|c: char| c.is_digit(10) || c == '.'), usize::from_str)(input)?;
    let mut spec = cell.take();
    spec.reliability = reliability;
    cell.set(spec);

    Ok((input, ()))
}

fn opennic_spec_params_ipv<'a>(cell: &Cell<OpenNic>, input: &'a str) -> IResult<&'a str, ()> {
    let (input, _) = tag("ipv=")(input)?;
    let (input, ipv) = map_res(take_while1(|c: char| c.is_digit(10) || c == '.'), IPV::from_str)(input)?;
    let mut spec = cell.take();
    spec.ipv = ipv;
    cell.set(spec);

    Ok((input, ()))
}

#[cfg(test)]
mod tests {
    use spectral::prelude::*;

    use crate::services::server_lists::PublicDns;

    use super::*;

    #[test]
    fn public_dns_default() {
        crate::utils::tests::logging::init();
        let str = "public-dns";
        let expected = ServerListSpec::PublicDns {
            spec: Default::default(),
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn public_country() {
        crate::utils::tests::logging::init();
        let str = "public-dns:de";
        let expected = ServerListSpec::PublicDns {
            spec: PublicDns {
                country: Some("de".to_string()),
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn public_separator_missing_country() {
        crate::utils::tests::logging::init();
        let str = "public-dns:";

        let res = parse_server_list_spec(&str);

        assert_that(&res).is_err();
    }

    #[test]
    fn opennic_default() {
        crate::utils::tests::logging::init();
        let str = "opennic";
        let expected = ServerListSpec::OpenNic {
            spec: Default::default(),
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
        assert_that(&config.opennic())
            .is_some()
            .map(|x| &x.anon)
            .is_equal_to(false);
    }

    #[test]
    fn opennic_anon() {
        crate::utils::tests::logging::init();
        let str = "opennic:anon";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                anon: true,
                ..Default::default()
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
        assert_that(&config.opennic())
            .is_some()
            .map(|x| &x.anon)
            .is_equal_to(true);
    }

    #[test]
    fn opennic_number() {
        crate::utils::tests::logging::init();
        let str = "opennic:number=100";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                number: 100,
                ..Default::default()
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn opennic_reliability() {
        crate::utils::tests::logging::init();
        let str = "opennic:reliability=40";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                reliability: 40,
                ..Default::default()
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn opennic_ipv4() {
        crate::utils::tests::logging::init();
        let str = "opennic:ipv=4";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                ipv: IPV::V4,
                ..Default::default()
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }

    #[test]
    fn opennic_all() {
        crate::utils::tests::logging::init();
        let str = "opennic:anon,number=100,reliability=50,ipv=6";
        let expected = ServerListSpec::OpenNic {
            spec: OpenNic {
                anon: true,
                number: 100,
                reliability: 50,
                ipv: IPV::V6,
            },
        };

        let (_, config) = parse_server_list_spec(&str).expect("failed to parse server list spec");

        assert_that(&config).is_equal_to(expected);
    }
}
<|endoftext|>


<commit_before>#![allow(unknown_lints)]

use ty::layout::{HasDataLayout, Size};
use ty::subst::Substs;
use hir::def_id::DefId;

use super::{EvalResult, Pointer, PointerArithmetic, Allocation};

/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
    /// Never returned from the `const_eval` query, but the HIR contains these frequently in order
    /// to allow HIR creation to happen for everything before needing to be able to run constant
    /// evaluation
    Unevaluated(DefId, &'tcx Substs<'tcx>),
    /// Used only for types with layout::abi::Scalar ABI and ZSTs
    ///
    /// Not using the enum `Value` to encode that this must not be `Undef`
    Scalar(Scalar),
    /// Used only for types with layout::abi::ScalarPair
    ///
    /// The second field may be undef in case of `Option<usize>::None`
    ScalarPair(Scalar, ScalarMaybeUndef),
    /// Used only for the remaining cases. An allocation + offset into the allocation
    ByRef(&'tcx Allocation, Size),
}

impl<'tcx> ConstValue<'tcx> {
    #[inline]
    pub fn try_to_scalar(&self) -> Option<Scalar> {
        match *self {
            ConstValue::Unevaluated(..) |
            ConstValue::ByRef(..) |
            ConstValue::ScalarPair(..) => None,
            ConstValue::Scalar(val) => Some(val),
        }
    }

    #[inline]
    pub fn try_to_bits(&self, size: Size) -> Option<u128> {
        self.try_to_scalar()?.to_bits(size).ok()
    }

    #[inline]
    pub fn try_to_ptr(&self) -> Option<Pointer> {
        self.try_to_scalar()?.to_ptr().ok()
    }

    pub fn new_slice(
        val: Scalar,
        len: u64,
        cx: impl HasDataLayout
    ) -> Self {
        ConstValue::ScalarPair(val, Scalar::Bits {
            bits: len as u128,
            size: cx.data_layout().pointer_size.bytes() as u8,
        }.into())
    }

    pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
        ConstValue::ScalarPair(val, Scalar::Ptr(vtable).into())
    }
}

impl<'tcx> Scalar {
    pub fn ptr_null(cx: impl HasDataLayout) -> Self {
        Scalar::Bits {
            bits: 0,
            size: cx.data_layout().pointer_size.bytes() as u8,
        }
    }

    pub fn zst() -> Self {
        Scalar::Bits { bits: 0, size: 0 }
    }

    pub fn ptr_signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.signed_offset(bits as u64, i)? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
        }
    }

    pub fn ptr_offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.offset(bits as u64, i.bytes())? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
        }
    }

    pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Scalar::Bits {
                    bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
                    size,
                }
            }
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, layout)),
        }
    }

    pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
        match self {
            Scalar::Bits { bits, size } =>  {
                assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
                bits == 0
            },
            Scalar::Ptr(_) => false,
        }
    }

    pub fn from_bool(b: bool) -> Self {
        Scalar::Bits { bits: b as u128, size: 1 }
    }

    pub fn from_char(c: char) -> Self {
        Scalar::Bits { bits: c as u128, size: 4 }
    }

    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(target_size.bytes(), size as u64);
                assert_ne!(size, 0, "to_bits cannot be used with zsts");
                Ok(bits)
            }
            Scalar::Ptr(_) => err!(ReadPointerAsBytes),
        }
    }

    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
        match self {
            Scalar::Bits {..} => err!(ReadBytesAsPointer),
            Scalar::Ptr(p) => Ok(p),
        }
    }

    pub fn is_bits(self) -> bool {
        match self {
            Scalar::Bits { .. } => true,
            _ => false,
        }
    }

    pub fn is_ptr(self) -> bool {
        match self {
            Scalar::Ptr(_) => true,
            _ => false,
        }
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits { bits: 0, size: 1 } => Ok(false),
            Scalar::Bits { bits: 1, size: 1 } => Ok(true),
            _ => err!(InvalidBool),
        }
    }
}

impl From<Pointer> for Scalar {
    fn from(ptr: Pointer) -> Self {
        Scalar::Ptr(ptr)
    }
}

/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Scalar {
    /// The raw bytes of a simple value.
    Bits {
        /// The first `size` bytes are the value.
        /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
        size: u8,
        bits: u128,
    },

    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
    /// relocation and its associated offset together as a `Pointer` here.
    Ptr(Pointer),
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum ScalarMaybeUndef {
    Scalar(Scalar),
    Undef,
}

impl From<Scalar> for ScalarMaybeUndef {
    fn from(s: Scalar) -> Self {
        ScalarMaybeUndef::Scalar(s)
    }
}

impl<'tcx> ScalarMaybeUndef {
    pub fn not_undef(self) -> EvalResult<'static, Scalar> {
        match self {
            ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
            ScalarMaybeUndef::Undef => err!(ReadUndefBytes),
        }
    }

    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
        self.not_undef()?.to_ptr()
    }

    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
        self.not_undef()?.to_bits(target_size)
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        self.not_undef()?.to_bool()
    }
}
<commit_msg>better error message when using NULL in to_ptr<commit_after>#![allow(unknown_lints)]

use ty::layout::{HasDataLayout, Size};
use ty::subst::Substs;
use hir::def_id::DefId;

use super::{EvalResult, Pointer, PointerArithmetic, Allocation};

/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
    /// Never returned from the `const_eval` query, but the HIR contains these frequently in order
    /// to allow HIR creation to happen for everything before needing to be able to run constant
    /// evaluation
    Unevaluated(DefId, &'tcx Substs<'tcx>),
    /// Used only for types with layout::abi::Scalar ABI and ZSTs
    ///
    /// Not using the enum `Value` to encode that this must not be `Undef`
    Scalar(Scalar),
    /// Used only for types with layout::abi::ScalarPair
    ///
    /// The second field may be undef in case of `Option<usize>::None`
    ScalarPair(Scalar, ScalarMaybeUndef),
    /// Used only for the remaining cases. An allocation + offset into the allocation
    ByRef(&'tcx Allocation, Size),
}

impl<'tcx> ConstValue<'tcx> {
    #[inline]
    pub fn try_to_scalar(&self) -> Option<Scalar> {
        match *self {
            ConstValue::Unevaluated(..) |
            ConstValue::ByRef(..) |
            ConstValue::ScalarPair(..) => None,
            ConstValue::Scalar(val) => Some(val),
        }
    }

    #[inline]
    pub fn try_to_bits(&self, size: Size) -> Option<u128> {
        self.try_to_scalar()?.to_bits(size).ok()
    }

    #[inline]
    pub fn try_to_ptr(&self) -> Option<Pointer> {
        self.try_to_scalar()?.to_ptr().ok()
    }

    pub fn new_slice(
        val: Scalar,
        len: u64,
        cx: impl HasDataLayout
    ) -> Self {
        ConstValue::ScalarPair(val, Scalar::Bits {
            bits: len as u128,
            size: cx.data_layout().pointer_size.bytes() as u8,
        }.into())
    }

    pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
        ConstValue::ScalarPair(val, Scalar::Ptr(vtable).into())
    }
}

impl<'tcx> Scalar {
    pub fn ptr_null(cx: impl HasDataLayout) -> Self {
        Scalar::Bits {
            bits: 0,
            size: cx.data_layout().pointer_size.bytes() as u8,
        }
    }

    pub fn zst() -> Self {
        Scalar::Bits { bits: 0, size: 0 }
    }

    pub fn ptr_signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.signed_offset(bits as u64, i)? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
        }
    }

    pub fn ptr_offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.offset(bits as u64, i.bytes())? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
        }
    }

    pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Scalar::Bits {
                    bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
                    size,
                }
            }
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, layout)),
        }
    }

    pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
        match self {
            Scalar::Bits { bits, size } =>  {
                assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
                bits == 0
            },
            Scalar::Ptr(_) => false,
        }
    }

    pub fn from_bool(b: bool) -> Self {
        Scalar::Bits { bits: b as u128, size: 1 }
    }

    pub fn from_char(c: char) -> Self {
        Scalar::Bits { bits: c as u128, size: 4 }
    }

    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(target_size.bytes(), size as u64);
                assert_ne!(size, 0, "to_bits cannot be used with zsts");
                Ok(bits)
            }
            Scalar::Ptr(_) => err!(ReadPointerAsBytes),
        }
    }

    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
        match self {
            Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
            Scalar::Bits { .. } => err!(ReadBytesAsPointer),
            Scalar::Ptr(p) => Ok(p),
        }
    }

    pub fn is_bits(self) -> bool {
        match self {
            Scalar::Bits { .. } => true,
            _ => false,
        }
    }

    pub fn is_ptr(self) -> bool {
        match self {
            Scalar::Ptr(_) => true,
            _ => false,
        }
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits { bits: 0, size: 1 } => Ok(false),
            Scalar::Bits { bits: 1, size: 1 } => Ok(true),
            _ => err!(InvalidBool),
        }
    }
}

impl From<Pointer> for Scalar {
    fn from(ptr: Pointer) -> Self {
        Scalar::Ptr(ptr)
    }
}

/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Scalar {
    /// The raw bytes of a simple value.
    Bits {
        /// The first `size` bytes are the value.
        /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
        size: u8,
        bits: u128,
    },

    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
    /// relocation and its associated offset together as a `Pointer` here.
    Ptr(Pointer),
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum ScalarMaybeUndef {
    Scalar(Scalar),
    Undef,
}

impl From<Scalar> for ScalarMaybeUndef {
    fn from(s: Scalar) -> Self {
        ScalarMaybeUndef::Scalar(s)
    }
}

impl<'tcx> ScalarMaybeUndef {
    pub fn not_undef(self) -> EvalResult<'static, Scalar> {
        match self {
            ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
            ScalarMaybeUndef::Undef => err!(ReadUndefBytes),
        }
    }

    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
        self.not_undef()?.to_ptr()
    }

    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
        self.not_undef()?.to_bits(target_size)
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        self.not_undef()?.to_bool()
    }
}
<|endoftext|>


<commit_before>use super::diagnostics::Error;
use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::PResult;
use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath {
    name: String,
    path_exists: bool,
    pub result: Result<ModulePathSuccess, Error>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub directory_ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let (module, attrs) = self.parse_mod(&token::Eof)?;
        let span = lo.to(self.token.span);
        let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
        Ok(ast::Crate { attrs, module, span, proc_macros })
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                // This mod is in an external file. Let's go get it!
                let ModulePathSuccess { path, directory_ownership } =
                    self.submod_path(id, &attrs)?;
                self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)?
            } else {
                (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
            }
        } else {
            let old_directory = self.directory.clone();
            self.push_directory(id, &attrs);

            self.expect(&token::OpenDelim(token::Brace))?;
            let module = self.parse_mod(&token::CloseDelim(token::Brace))?;

            self.directory = old_directory;
            module
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Parses the contents of a module (inner attributes followed by module items).
    fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let lo = self.token.span;
        let attrs = self.parse_inner_attributes()?;
        let module = self.parse_mod_items(term, lo)?;
        Ok((module, attrs))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }

    fn submod_path(
        &mut self,
        id: ast::Ident,
        outer_attrs: &[Attribute],
    ) -> PResult<'a, ModulePathSuccess> {
        if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
            let directory_ownership = match path.file_name().and_then(|s| s.to_str()) {
                // All `#[path]` files are treated as though they are a `mod.rs` file.
                // This means that `mod foo;` declarations inside `#[path]`-included
                // files are siblings,
                //
                // Note that this will produce weirdness when a file named `foo.rs` is
                // `#[path]` included and contains a `mod foo;` declaration.
                // If you encounter this, it's your own darn fault :P
                Some(_) => DirectoryOwnership::Owned { relative: None },
                _ => DirectoryOwnership::UnownedViaMod,
            };
            return Ok(ModulePathSuccess { directory_ownership, path });
        }

        let relative = match self.directory.ownership {
            DirectoryOwnership::Owned { relative } => relative,
            DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
        };
        let paths =
            Parser::default_submod_path(id, relative, &self.directory.path, self.sess.source_map());

        match self.directory.ownership {
            DirectoryOwnership::Owned { .. } => {
                paths.result.map_err(|err| self.span_fatal_err(id.span, err))
            }
            DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id.span, paths),
            DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id.span, paths),
        }
    }

    fn error_decl_mod_in_block<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let msg =
            "Cannot declare a non-inline module inside a block unless it has a path attribute";
        let mut err = self.struct_span_err(id_sp, msg);
        if paths.path_exists {
            let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", paths.name);
            err.span_note(id_sp, &msg);
        }
        Err(err)
    }

    fn error_cannot_declare_mod_here<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location");
        if !id_sp.is_dummy() {
            if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) {
                if let Some(stem) = src_path.file_stem() {
                    let mut dest_path = src_path.clone();
                    dest_path.set_file_name(stem);
                    dest_path.push("mod.rs");
                    err.span_note(
                        id_sp,
                        &format!(
                            "maybe move this module `{}` to its own \
                                    directory via `{}`",
                            src_path.display(),
                            dest_path.display()
                        ),
                    );
                }
            }
        }
        if paths.path_exists {
            err.span_note(
                id_sp,
                &format!(
                    "... or maybe `use` the module `{}` instead \
                                of possibly redeclaring it",
                    paths.name
                ),
            );
        }
        Err(err)
    }

    /// Derive a submodule path from the first found `#[path = "path_string"]`.
    /// The provided `dir_path` is joined with the `path_string`.
    // Public for rustfmt usage.
    pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
        // Extract path string from first `#[path = "path_string"]` attribute.
        let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
        let path_string = path_string.as_str();

        // On windows, the base path might have the form
        // `\\?\foo\bar` in which case it does not tolerate
        // mixed `/` and `\` separators, so canonicalize
        // `/` to `\`.
        #[cfg(windows)]
        let path_string = path_string.replace("/", "\\");

        Some(dir_path.join(&*path_string))
    }

    /// Returns a path to a module.
    // Public for rustfmt usage.
    pub fn default_submod_path(
        id: ast::Ident,
        relative: Option<ast::Ident>,
        dir_path: &Path,
        source_map: &SourceMap,
    ) -> ModulePath {
        // If we're in a foo.rs file instead of a mod.rs file,
        // we need to look for submodules in
        // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
        // `./<id>.rs` and `./<id>/mod.rs`.
        let relative_prefix_string;
        let relative_prefix = if let Some(ident) = relative {
            relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
            &relative_prefix_string
        } else {
            ""
        };

        let mod_name = id.name.to_string();
        let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
        let secondary_path_str =
            format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
        let default_path = dir_path.join(&default_path_str);
        let secondary_path = dir_path.join(&secondary_path_str);
        let default_exists = source_map.file_exists(&default_path);
        let secondary_exists = source_map.file_exists(&secondary_path);

        let result = match (default_exists, secondary_exists) {
            (true, false) => Ok(ModulePathSuccess {
                path: default_path,
                directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
            }),
            (false, true) => Ok(ModulePathSuccess {
                path: secondary_path,
                directory_ownership: DirectoryOwnership::Owned { relative: None },
            }),
            (false, false) => {
                Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), default_path })
            }
            (true, true) => Err(Error::DuplicatePaths {
                mod_name: mod_name.clone(),
                default_path: default_path_str,
                secondary_path: secondary_path_str,
            }),
        };

        ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
    }

    /// Reads a module from a source file.
    fn eval_src_mod(
        &mut self,
        path: PathBuf,
        directory_ownership: DirectoryOwnership,
        name: String,
        id_sp: Span,
    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
        if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
            let mut err = String::from("circular modules: ");
            let len = included_mod_stack.len();
            for p in &included_mod_stack[i..len] {
                err.push_str(&p.to_string_lossy());
                err.push_str(" -> ");
            }
            err.push_str(&path.to_string_lossy());
            return Err(self.struct_span_err(id_sp, &err[..]));
        }
        included_mod_stack.push(path.clone());
        drop(included_mod_stack);

        let mut p0 =
            new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
        p0.cfg_mods = self.cfg_mods;
        let mut module = p0.parse_mod(&token::Eof)?;
        module.0.inline = false;

        self.sess.included_mod_stack.borrow_mut().pop();
        Ok(module)
    }

    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
        if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
            self.directory.path.push(&*path.as_str());
            self.directory.ownership = DirectoryOwnership::Owned { relative: None };
        } else {
            // We have to push on the current module name in the case of relative
            // paths in order to ensure that any additional module paths from inline
            // `mod x { ... }` come after the relative extension.
            //
            // For example, a `mod z { ... }` inside `x/y.rs` should set the current
            // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
            if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership {
                if let Some(ident) = relative.take() {
                    // remove the relative offset
                    self.directory.path.push(&*ident.as_str());
                }
            }
            self.directory.path.push(&*id.as_str());
        }
    }
}
<commit_msg>extract error_on_circular_module<commit_after>use super::diagnostics::Error;
use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::PResult;
use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath {
    name: String,
    path_exists: bool,
    pub result: Result<ModulePathSuccess, Error>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub directory_ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let (module, attrs) = self.parse_mod(&token::Eof)?;
        let span = lo.to(self.token.span);
        let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
        Ok(ast::Crate { attrs, module, span, proc_macros })
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                // This mod is in an external file. Let's go get it!
                let ModulePathSuccess { path, directory_ownership } =
                    self.submod_path(id, &attrs)?;
                self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)?
            } else {
                (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
            }
        } else {
            let old_directory = self.directory.clone();
            self.push_directory(id, &attrs);

            self.expect(&token::OpenDelim(token::Brace))?;
            let module = self.parse_mod(&token::CloseDelim(token::Brace))?;

            self.directory = old_directory;
            module
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Parses the contents of a module (inner attributes followed by module items).
    fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let lo = self.token.span;
        let attrs = self.parse_inner_attributes()?;
        let module = self.parse_mod_items(term, lo)?;
        Ok((module, attrs))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }

    fn submod_path(
        &mut self,
        id: ast::Ident,
        outer_attrs: &[Attribute],
    ) -> PResult<'a, ModulePathSuccess> {
        if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
            let directory_ownership = match path.file_name().and_then(|s| s.to_str()) {
                // All `#[path]` files are treated as though they are a `mod.rs` file.
                // This means that `mod foo;` declarations inside `#[path]`-included
                // files are siblings,
                //
                // Note that this will produce weirdness when a file named `foo.rs` is
                // `#[path]` included and contains a `mod foo;` declaration.
                // If you encounter this, it's your own darn fault :P
                Some(_) => DirectoryOwnership::Owned { relative: None },
                _ => DirectoryOwnership::UnownedViaMod,
            };
            return Ok(ModulePathSuccess { directory_ownership, path });
        }

        let relative = match self.directory.ownership {
            DirectoryOwnership::Owned { relative } => relative,
            DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
        };
        let paths =
            Parser::default_submod_path(id, relative, &self.directory.path, self.sess.source_map());

        match self.directory.ownership {
            DirectoryOwnership::Owned { .. } => {
                paths.result.map_err(|err| self.span_fatal_err(id.span, err))
            }
            DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id.span, paths),
            DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id.span, paths),
        }
    }

    fn error_decl_mod_in_block<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let msg =
            "Cannot declare a non-inline module inside a block unless it has a path attribute";
        let mut err = self.struct_span_err(id_sp, msg);
        if paths.path_exists {
            let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", paths.name);
            err.span_note(id_sp, &msg);
        }
        Err(err)
    }

    fn error_cannot_declare_mod_here<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location");
        if !id_sp.is_dummy() {
            if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) {
                if let Some(stem) = src_path.file_stem() {
                    let mut dest_path = src_path.clone();
                    dest_path.set_file_name(stem);
                    dest_path.push("mod.rs");
                    err.span_note(
                        id_sp,
                        &format!(
                            "maybe move this module `{}` to its own \
                                    directory via `{}`",
                            src_path.display(),
                            dest_path.display()
                        ),
                    );
                }
            }
        }
        if paths.path_exists {
            err.span_note(
                id_sp,
                &format!(
                    "... or maybe `use` the module `{}` instead \
                                of possibly redeclaring it",
                    paths.name
                ),
            );
        }
        Err(err)
    }

    /// Derive a submodule path from the first found `#[path = "path_string"]`.
    /// The provided `dir_path` is joined with the `path_string`.
    // Public for rustfmt usage.
    pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
        // Extract path string from first `#[path = "path_string"]` attribute.
        let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
        let path_string = path_string.as_str();

        // On windows, the base path might have the form
        // `\\?\foo\bar` in which case it does not tolerate
        // mixed `/` and `\` separators, so canonicalize
        // `/` to `\`.
        #[cfg(windows)]
        let path_string = path_string.replace("/", "\\");

        Some(dir_path.join(&*path_string))
    }

    /// Returns a path to a module.
    // Public for rustfmt usage.
    pub fn default_submod_path(
        id: ast::Ident,
        relative: Option<ast::Ident>,
        dir_path: &Path,
        source_map: &SourceMap,
    ) -> ModulePath {
        // If we're in a foo.rs file instead of a mod.rs file,
        // we need to look for submodules in
        // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
        // `./<id>.rs` and `./<id>/mod.rs`.
        let relative_prefix_string;
        let relative_prefix = if let Some(ident) = relative {
            relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
            &relative_prefix_string
        } else {
            ""
        };

        let mod_name = id.name.to_string();
        let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
        let secondary_path_str =
            format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
        let default_path = dir_path.join(&default_path_str);
        let secondary_path = dir_path.join(&secondary_path_str);
        let default_exists = source_map.file_exists(&default_path);
        let secondary_exists = source_map.file_exists(&secondary_path);

        let result = match (default_exists, secondary_exists) {
            (true, false) => Ok(ModulePathSuccess {
                path: default_path,
                directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
            }),
            (false, true) => Ok(ModulePathSuccess {
                path: secondary_path,
                directory_ownership: DirectoryOwnership::Owned { relative: None },
            }),
            (false, false) => {
                Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), default_path })
            }
            (true, true) => Err(Error::DuplicatePaths {
                mod_name: mod_name.clone(),
                default_path: default_path_str,
                secondary_path: secondary_path_str,
            }),
        };

        ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
    }

    /// Reads a module from a source file.
    fn eval_src_mod(
        &mut self,
        path: PathBuf,
        directory_ownership: DirectoryOwnership,
        name: String,
        id_sp: Span,
    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
        self.error_on_circular_module(id_sp, &path, &included_mod_stack)?;
        included_mod_stack.push(path.clone());
        drop(included_mod_stack);

        let mut p0 =
            new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
        p0.cfg_mods = self.cfg_mods;
        let mut module = p0.parse_mod(&token::Eof)?;
        module.0.inline = false;

        self.sess.included_mod_stack.borrow_mut().pop();
        Ok(module)
    }

    fn error_on_circular_module(
        &self,
        span: Span,
        path: &Path,
        included_mod_stack: &[PathBuf],
    ) -> PResult<'a, ()> {
        if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
            let mut err = String::from("circular modules: ");
            let len = included_mod_stack.len();
            for p in &included_mod_stack[i..len] {
                err.push_str(&p.to_string_lossy());
                err.push_str(" -> ");
            }
            err.push_str(&path.to_string_lossy());
            return Err(self.struct_span_err(span, &err[..]));
        }
        Ok(())
    }

    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
        if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
            self.directory.path.push(&*path.as_str());
            self.directory.ownership = DirectoryOwnership::Owned { relative: None };
        } else {
            // We have to push on the current module name in the case of relative
            // paths in order to ensure that any additional module paths from inline
            // `mod x { ... }` come after the relative extension.
            //
            // For example, a `mod z { ... }` inside `x/y.rs` should set the current
            // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
            if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership {
                if let Some(ident) = relative.take() {
                    // remove the relative offset
                    self.directory.path.push(&*ident.as_str());
                }
            }
            self.directory.path.push(&*id.as_str());
        }
    }
}
<|endoftext|>


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

extern crate image;
extern crate glob;

const BASE_PATH: [&'static str; 2] = [".", "tests"];
const IMAGE_DIR: &'static str = "images";
const OUTPUT_DIR: &'static str = "output";
const REFERENCE_DIR: &'static str = "reference";

fn process_images<F>(dir: &str, input_decoder: Option<&str>, func: F)
where F: Fn(&PathBuf, PathBuf, &str) {
	let base: PathBuf = BASE_PATH.iter().collect();
	let decoders = &["tga", "tiff", "png"];
	for decoder in decoders {
		let mut path = base.clone();
		path.push(dir);
		path.push(decoder);
		path.push("*");
		path.push("*.".to_string() + match input_decoder {
			Some(val) => val,
			None => decoder
		});
		let pattern = &*format!("{}", path.display());
		for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
			func(&base, path, decoder)
		}
	}
}

#[test]
fn render_images() {
	process_images(IMAGE_DIR, None, |base, path, decoder| {
		let img = match image::open(&path) {
			Ok(img) => img.to_rgba(),
			/// Do not fail on unsupported error
			/// This might happen because the testsuite contains unsupported images
			/// or because a specific decoder included via a feature.
			Err(image::ImageError::UnsupportedError(_)) => return,
			Err(err) => panic!(format!("{}", err))
		};
		let mut crc = Crc32::new();
		crc.update(&*img);

		let (filename, testsuite) = {
			let mut path: Vec<_> = path.components().collect();
			(path.pop().unwrap(), path.pop().unwrap())
		};
		let mut out_path = base.clone();

		out_path.push(OUTPUT_DIR);
		out_path.push(decoder);
		out_path.push(testsuite.as_os_str());
		fs::create_dir_all(&out_path).unwrap();
		out_path.push(format!("{}.{}.{}",
			filename.as_os_str().to_str().unwrap(),
			format!("{:x}", crc.checksum()),
			"png"
		));
		img.save(out_path).unwrap();
	})
}

#[test]
fn check_references() {
	process_images(REFERENCE_DIR, Some("png"), |base, path, decoder| {
        let ref_img = match image::open(&path) {
            Ok(img) => img.to_rgba(),
            /// Do not fail on unsupported error
            /// This might happen because the testsuite contains unsupported images
            /// or because a specific decoder included via a feature.
            Err(image::ImageError::UnsupportedError(_)) => return,
            Err(err) => panic!(format!("{}", err))
        };

		let (filename, testsuite) = {
			let mut path: Vec<_> = path.components().collect();
			(path.pop().unwrap(), path.pop().unwrap())
		};
		let mut img_path = base.clone();
		img_path.push(IMAGE_DIR);
		img_path.push(decoder);
		img_path.push(testsuite.as_os_str());
		img_path.push(filename
			.as_os_str()
			.to_str()
			.unwrap()
			.split(".")
			.take(2)
			.collect::<Vec<_>>().connect(".")
		);
        let test_img = match image::open(&img_path) {
            Ok(img) => img.to_rgba(),
            /// Do not fail on unsupported error
            /// This might happen because the testsuite contains unsupported images
            /// or because a specific decoder included via a feature.
            Err(image::ImageError::UnsupportedError(_)) => return,
            Err(err) => panic!(format!("{}", err))
        };
		if &*ref_img != &*test_img {
			panic!("Reference rendering does not match for image at {:?}.", img_path)
		}
	})
}

const CRC_TABLE: [u32; 256] = [
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
    0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
    0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
    0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
    0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
    0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
    0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
    0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
    0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
    0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
    0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
    0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
    0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
    0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
    0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
    0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
    0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
    0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
    0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
    0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
    0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
    0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
    0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
    0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
    0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
    0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
    0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
    0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
    0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
    0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
    0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
    0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
    0x2d02ef8d
];

/// An Implementation of the Crc-32 checksum
/// This is copied from png::hash such that it does not have to be exposed in the public interface
pub struct Crc32 {
    crc: u32,
}

impl Crc32 {
    /// Create a new hasher.
    pub fn new() -> Crc32 {
        Crc32 {crc: 0xFFFFFFFF}
    }

    /// Update the internal hasher with the bytes from ```buf```
    pub fn update(&mut self, buf: &[u8]) {
        for &byte in buf {
            let a = (self.crc ^ byte as u32) & 0xFF;
            let b = self.crc >> 8;

            self.crc = CRC_TABLE[a as usize] ^ b;
        }
    }

    /// Return the computed hash.
    pub fn checksum(&self) -> u32 {
        self.crc ^ 0xFFFFFFFF
    }

    /// Reset this hasher to its initial state.
    pub fn reset(&mut self) {
        self.crc = 0xFFFFFFFF;
    }
}
<commit_msg>Improve error message<commit_after>use std::path::PathBuf;
use std::fs;

extern crate image;
extern crate glob;

const BASE_PATH: [&'static str; 2] = [".", "tests"];
const IMAGE_DIR: &'static str = "images";
const OUTPUT_DIR: &'static str = "output";
const REFERENCE_DIR: &'static str = "reference";

fn process_images<F>(dir: &str, input_decoder: Option<&str>, func: F)
where F: Fn(&PathBuf, PathBuf, &str) {
	let base: PathBuf = BASE_PATH.iter().collect();
	let decoders = &["tga", "tiff", "png"];
	for decoder in decoders {
		let mut path = base.clone();
		path.push(dir);
		path.push(decoder);
		path.push("*");
		path.push("*.".to_string() + match input_decoder {
			Some(val) => val,
			None => decoder
		});
		let pattern = &*format!("{}", path.display());
		for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
			func(&base, path, decoder)
		}
	}
}

#[test]
fn render_images() {
	process_images(IMAGE_DIR, None, |base, path, decoder| {
		let img = match image::open(&path) {
			Ok(img) => img.to_rgba(),
			/// Do not fail on unsupported error
			/// This might happen because the testsuite contains unsupported images
			/// or because a specific decoder included via a feature.
			Err(image::ImageError::UnsupportedError(_)) => return,
			Err(err) => panic!(format!("decoding of {:?} failed with: {}", path, err))
		};
		let mut crc = Crc32::new();
		crc.update(&*img);

		let (filename, testsuite) = {
			let mut path: Vec<_> = path.components().collect();
			(path.pop().unwrap(), path.pop().unwrap())
		};
		let mut out_path = base.clone();

		out_path.push(OUTPUT_DIR);
		out_path.push(decoder);
		out_path.push(testsuite.as_os_str());
		fs::create_dir_all(&out_path).unwrap();
		out_path.push(format!("{}.{}.{}",
			filename.as_os_str().to_str().unwrap(),
			format!("{:x}", crc.checksum()),
			"png"
		));
		img.save(out_path).unwrap();
	})
}

#[test]
fn check_references() {
	process_images(REFERENCE_DIR, Some("png"), |base, path, decoder| {
        let ref_img = match image::open(&path) {
            Ok(img) => img.to_rgba(),
            /// Do not fail on unsupported error
            /// This might happen because the testsuite contains unsupported images
            /// or because a specific decoder included via a feature.
            Err(image::ImageError::UnsupportedError(_)) => return,
            Err(err) => panic!(format!("{}", err))
        };

		let (filename, testsuite) = {
			let mut path: Vec<_> = path.components().collect();
			(path.pop().unwrap(), path.pop().unwrap())
		};
		let mut img_path = base.clone();
		img_path.push(IMAGE_DIR);
		img_path.push(decoder);
		img_path.push(testsuite.as_os_str());
		img_path.push(filename
			.as_os_str()
			.to_str()
			.unwrap()
			.split(".")
			.take(2)
			.collect::<Vec<_>>().connect(".")
		);
        let test_img = match image::open(&img_path) {
            Ok(img) => img.to_rgba(),
            /// Do not fail on unsupported error
            /// This might happen because the testsuite contains unsupported images
            /// or because a specific decoder included via a feature.
            Err(image::ImageError::UnsupportedError(_)) => return,
            Err(err) => panic!(format!("decoding of {:?} failed with: {}", path, err))
        };
		if &*ref_img != &*test_img {
			panic!("Reference rendering does not match for image at {:?}.", img_path)
		}
	})
}

const CRC_TABLE: [u32; 256] = [
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
    0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
    0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
    0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
    0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
    0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
    0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
    0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
    0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
    0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
    0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
    0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
    0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
    0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
    0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
    0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
    0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
    0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
    0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
    0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
    0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
    0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
    0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
    0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
    0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
    0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
    0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
    0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
    0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
    0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
    0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
    0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
    0x2d02ef8d
];

/// An Implementation of the Crc-32 checksum
/// This is copied from png::hash such that it does not have to be exposed in the public interface
pub struct Crc32 {
    crc: u32,
}

impl Crc32 {
    /// Create a new hasher.
    pub fn new() -> Crc32 {
        Crc32 {crc: 0xFFFFFFFF}
    }

    /// Update the internal hasher with the bytes from ```buf```
    pub fn update(&mut self, buf: &[u8]) {
        for &byte in buf {
            let a = (self.crc ^ byte as u32) & 0xFF;
            let b = self.crc >> 8;

            self.crc = CRC_TABLE[a as usize] ^ b;
        }
    }

    /// Return the computed hash.
    pub fn checksum(&self) -> u32 {
        self.crc ^ 0xFFFFFFFF
    }

    /// Reset this hasher to its initial state.
    pub fn reset(&mut self) {
        self.crc = 0xFFFFFFFF;
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate rls_analysis as analysis;
extern crate rls_data as data;
extern crate serde;
#[macro_use]
extern crate serde_json;

use data::GlobalCrateId;
use analysis::{AnalysisHost, AnalysisLoader};
use std::collections::HashMap;
use std::fs::{self, File};
use std::path::{Path, PathBuf};

/// A global definition id in a crate.
///
/// FIXME(emilio): This key is kind of slow, because GlobalCrateId contains a
/// String. There's a "disambiguator" field which may be more than enough for
/// our purposes.
#[derive(Clone, Hash, Debug, Eq, PartialEq)]
pub struct DefId(GlobalCrateId, u32);

/// A map from global definition ids to the actual definition.
pub struct Defs {
    map: HashMap<DefId, data::Def>,
}

impl Defs {
    fn new() -> Self {
        Self { map: HashMap::new() }
    }

    fn insert(&mut self, analysis: &data::Analysis, def: &data::Def) {
        let crate_id = analysis.prelude.as_ref().unwrap().crate_id.clone();
        let mut definition = def.clone();
        let crate_independent_qualname =
            format!("{}{}", crate_id.name, def.qualname);
        definition.qualname = crate_independent_qualname;

        let index = definition.id.index;
        let previous = self.map.insert(DefId(crate_id, index), definition);
        assert!(
            previous.is_none(),
            "Found a definition with the same ID twice? {:?}",
            def,
        );
    }

    /// Getter for a given local id, which takes care of converting to a global
    /// ID and returning the definition if present.
    fn get(&self, analysis: &data::Analysis, id: data::Id) -> Option<data::Def> {
        let prelude = analysis.prelude.as_ref().unwrap();
        let krate_id = if id.krate == 0 {
            prelude.crate_id.clone()
        } else {
            // TODO(emilio): This escales with the number of crates in this
            // particular crate, but it's probably not too bad, since it should
            // be a pretty fast linear search.
            let krate = prelude.external_crates.iter().find(|krate| {
                krate.num == id.krate
            });

            let krate = match krate {
                Some(k) => k,
                None => {
                    eprintln!("Crate not found: {:?}", id);
                    return None;
                }
            };

            krate.id.clone()
        };

        let id = DefId(krate_id, id.index);
        self.map.get(&id).cloned()
    }
}

#[derive(Clone)]
pub struct Loader {
    deps_dir: PathBuf,
}

impl Loader {
    pub fn new(deps_dir: PathBuf) -> Self {
        Self { deps_dir }
    }
}

impl AnalysisLoader for Loader {
    fn needs_hard_reload(&self, _: &Path) -> bool {
        true
    }

    fn fresh_host(&self) -> AnalysisHost<Self> {
        AnalysisHost::new_with_loader(self.clone())
    }

    fn set_path_prefix(&mut self, _: &Path) {}

    fn abs_path_prefix(&self) -> Option<PathBuf> {
        None
    }
    fn search_directories(&self) -> Vec<PathBuf> {
        vec![self.deps_dir.clone()]
    }
}

// Searchfox uses 1-indexed lines, 0-indexed columns.
fn span_to_string(span: &data::SpanData) -> String {
    // Rust spans are multi-line... So we just set the start column if it spans
    // multiple rows, searchfox has fallback code to handle this.
    if span.line_start != span.line_end {
        return format!("{}:{}", span.line_start.0, span.column_start.0 - 1);
    }
    if span.column_start == span.column_end {
        return format!("{}:{}", span.line_start.0, span.column_start.0 - 1);
    }
    let len = span.column_end.0 - span.column_start.0;
    format!("{}:{}-{}", span.line_start.0, span.column_start.0 - 1, len)
}

fn visit(
    file: &mut File,
    kind: &'static str,
    location: &data::SpanData,
    qualname: &str,
    context: Option<&str>,
) {
    use serde_json::map::Map;
    use serde_json::value::Value;
    use std::io::Write;

    let mut out = Map::new();
    out.insert("loc".into(), Value::String(span_to_string(location)));
    out.insert("target".into(), json!(1));
    out.insert("kind".into(), Value::String(kind.into()));
    out.insert("pretty".into(), Value::String(qualname.into()));
    out.insert("sym".into(), Value::String(qualname.into()));
    if let Some(context) = context {
        out.insert("context".into(), Value::String(context.into()));
        out.insert("contextsym".into(), Value::String(context.into()));
    }

    let object = serde_json::to_string(&Value::Object(out)).unwrap();
    file.write_all(object.as_bytes()).unwrap();
    write!(file, "\n").unwrap();

    let mut out = Map::new();
    out.insert("loc".into(), Value::String(span_to_string(location)));
    out.insert("source".into(), json!(1));
    out.insert("kind".into(), Value::String(kind.into()));
    out.insert("pretty".into(), Value::String(qualname.into()));
    out.insert("sym".into(), Value::String(qualname.into()));

    let object = serde_json::to_string(&Value::Object(out)).unwrap();
    file.write_all(object.as_bytes()).unwrap();
    write!(file, "\n").unwrap();
}

fn analyze_file(
    file_name: &PathBuf,
    defs: &Defs,
    file_analysis: &data::Analysis,
    src_dir: &Path,
    output_dir: &Path,
) {
    let file = match file_name.strip_prefix(src_dir) {
        Ok(f) => f,
        Err(..) => {
            eprintln!("File not in the source directory: {}", file_name.display());
            return;
        }
    };

    let output_file = output_dir.join(file);
    let mut output_dir = output_file.clone();
    output_dir.pop();
    if let Err(err) = fs::create_dir_all(output_dir) {
        eprintln!(
            "Couldn't create dir for: {}, {:?}",
            output_file.display(),
            err
        );
        return;
    }
    let mut file = match File::create(&output_file) {
        Ok(f) => f,
        Err(err) => {
            eprintln!(
                "Couldn't open output file: {}, {:?}",
                output_file.display(),
                err
            );
            return;
        }
    };

    for import in &file_analysis.imports {
        let id = match import.ref_id {
            Some(id) => id,
            None => {
                eprintln!("Dropping import {}: {}, no ref", import.name, import.value);
                continue;
            }
        };

        let def = match defs.get(file_analysis, id) {
            Some(def) => def,
            None => {
                eprintln!("Dropping import {}: {}, no def for ref {:?}", import.name, import.value, id);
                continue;
            }
        };

        visit(&mut file, "use", &import.span, &def.qualname, None)
    }

    for def in &file_analysis.defs {
        let parent = def.parent
            .and_then(|parent_id| defs.get(file_analysis, parent_id).map(|d| d.qualname));

        let crate_name = &file_analysis.prelude.as_ref().unwrap().crate_id.name;
        let qualname = format!("{}{}", crate_name, def.qualname);
        visit(&mut file, "def", &def.span, &qualname, parent.as_ref().map(|p| &**p))
    }

    for ref_ in &file_analysis.refs {
        let def = match defs.get(file_analysis, ref_.ref_id) {
            Some(d) => d,
            None => {
                eprintln!("Dropping ref {:?}, kind {:?}, no def", ref_.ref_id, ref_.kind);
                continue;
            }
        };
        visit(
            &mut file,
            "use",
            &ref_.span,
            &def.qualname,
            /* context = */ None, // TODO
        )
    }
}

fn analyze_crate(
    analysis: &data::Analysis,
    defs: &Defs,
    src_dir: &Path,
    output_dir: &Path,
) {
    let mut per_file = HashMap::new();

    println!("Analyzing crate: {:?}", analysis.prelude);

    macro_rules! flat_map_per_file {
        ($field:ident) => {
            for item in &analysis.$field {
                let mut file_analysis =
                    per_file.entry(item.span.file_name.clone())
                        .or_insert_with(|| {
                            let prelude = analysis.prelude.clone();
                            let mut analysis = data::Analysis::new(analysis.config.clone());
                            analysis.prelude = prelude;
                            analysis
                        });
                file_analysis.$field.push(item.clone());
            }
        }
    }

    flat_map_per_file!(imports);
    flat_map_per_file!(defs);
    flat_map_per_file!(impls);
    flat_map_per_file!(refs);
    flat_map_per_file!(macro_refs);
    flat_map_per_file!(relations);

    for (mut name, analysis) in per_file.drain() {
        if name.is_relative() {
            name = src_dir.join(name);
        }
        analyze_file(&name, defs, &analysis, src_dir, output_dir);
    }
}

fn main() {
    let matches = app_from_crate!()
        .args_from_usage(
            "<src>    'Points to the source root'
             <input>  'Points to the deps/save-analysis directory'
             <output> 'Points to the directory where searchfox metadata should'",
        )
        .get_matches();

    let src_dir = Path::new(matches.value_of("src").unwrap());
    let input_dir = Path::new(matches.value_of("input").unwrap());
    let output_dir = Path::new(matches.value_of("output").unwrap());

    let loader = Loader::new(PathBuf::from(input_dir));

    let crates = analysis::read_analysis_from_files(&loader, Default::default(), &[]);

    let mut defs = Defs::new();
    for krate in &crates {
        for def in &krate.analysis.defs {
            println!("Indexing def: {:?}", def);
            defs.insert(&krate.analysis, def);
        }
    }

    for krate in crates {
        analyze_crate(&krate.analysis, &defs, &src_dir, &output_dir);
    }
}
<commit_msg>rust-indexer: Don't rename rls_analysis.<commit_after>#[macro_use]
extern crate clap;
extern crate rls_analysis;
extern crate rls_data as data;
extern crate serde;
#[macro_use]
extern crate serde_json;

use data::GlobalCrateId;
use rls_analysis::{AnalysisHost, AnalysisLoader};
use std::collections::HashMap;
use std::fs::{self, File};
use std::path::{Path, PathBuf};

/// A global definition id in a crate.
///
/// FIXME(emilio): This key is kind of slow, because GlobalCrateId contains a
/// String. There's a "disambiguator" field which may be more than enough for
/// our purposes.
#[derive(Clone, Hash, Debug, Eq, PartialEq)]
pub struct DefId(GlobalCrateId, u32);

/// A map from global definition ids to the actual definition.
pub struct Defs {
    map: HashMap<DefId, data::Def>,
}

impl Defs {
    fn new() -> Self {
        Self { map: HashMap::new() }
    }

    fn insert(&mut self, analysis: &data::Analysis, def: &data::Def) {
        let crate_id = analysis.prelude.as_ref().unwrap().crate_id.clone();
        let mut definition = def.clone();
        let crate_independent_qualname =
            format!("{}{}", crate_id.name, def.qualname);
        definition.qualname = crate_independent_qualname;

        let index = definition.id.index;
        let previous = self.map.insert(DefId(crate_id, index), definition);
        assert!(
            previous.is_none(),
            "Found a definition with the same ID twice? {:?}",
            def,
        );
    }

    /// Getter for a given local id, which takes care of converting to a global
    /// ID and returning the definition if present.
    fn get(&self, analysis: &data::Analysis, id: data::Id) -> Option<data::Def> {
        let prelude = analysis.prelude.as_ref().unwrap();
        let krate_id = if id.krate == 0 {
            prelude.crate_id.clone()
        } else {
            // TODO(emilio): This escales with the number of crates in this
            // particular crate, but it's probably not too bad, since it should
            // be a pretty fast linear search.
            let krate = prelude.external_crates.iter().find(|krate| {
                krate.num == id.krate
            });

            let krate = match krate {
                Some(k) => k,
                None => {
                    eprintln!("Crate not found: {:?}", id);
                    return None;
                }
            };

            krate.id.clone()
        };

        let id = DefId(krate_id, id.index);
        self.map.get(&id).cloned()
    }
}

#[derive(Clone)]
pub struct Loader {
    deps_dir: PathBuf,
}

impl Loader {
    pub fn new(deps_dir: PathBuf) -> Self {
        Self { deps_dir }
    }
}

impl AnalysisLoader for Loader {
    fn needs_hard_reload(&self, _: &Path) -> bool {
        true
    }

    fn fresh_host(&self) -> AnalysisHost<Self> {
        AnalysisHost::new_with_loader(self.clone())
    }

    fn set_path_prefix(&mut self, _: &Path) {}

    fn abs_path_prefix(&self) -> Option<PathBuf> {
        None
    }
    fn search_directories(&self) -> Vec<PathBuf> {
        vec![self.deps_dir.clone()]
    }
}

// Searchfox uses 1-indexed lines, 0-indexed columns.
fn span_to_string(span: &data::SpanData) -> String {
    // Rust spans are multi-line... So we just set the start column if it spans
    // multiple rows, searchfox has fallback code to handle this.
    if span.line_start != span.line_end {
        return format!("{}:{}", span.line_start.0, span.column_start.0 - 1);
    }
    if span.column_start == span.column_end {
        return format!("{}:{}", span.line_start.0, span.column_start.0 - 1);
    }
    let len = span.column_end.0 - span.column_start.0;
    format!("{}:{}-{}", span.line_start.0, span.column_start.0 - 1, len)
}

fn visit(
    file: &mut File,
    kind: &'static str,
    location: &data::SpanData,
    qualname: &str,
    context: Option<&str>,
) {
    use serde_json::map::Map;
    use serde_json::value::Value;
    use std::io::Write;

    let mut out = Map::new();
    out.insert("loc".into(), Value::String(span_to_string(location)));
    out.insert("target".into(), json!(1));
    out.insert("kind".into(), Value::String(kind.into()));
    out.insert("pretty".into(), Value::String(qualname.into()));
    out.insert("sym".into(), Value::String(qualname.into()));
    if let Some(context) = context {
        out.insert("context".into(), Value::String(context.into()));
        out.insert("contextsym".into(), Value::String(context.into()));
    }

    let object = serde_json::to_string(&Value::Object(out)).unwrap();
    file.write_all(object.as_bytes()).unwrap();
    write!(file, "\n").unwrap();

    let mut out = Map::new();
    out.insert("loc".into(), Value::String(span_to_string(location)));
    out.insert("source".into(), json!(1));
    out.insert("kind".into(), Value::String(kind.into()));
    out.insert("pretty".into(), Value::String(qualname.into()));
    out.insert("sym".into(), Value::String(qualname.into()));

    let object = serde_json::to_string(&Value::Object(out)).unwrap();
    file.write_all(object.as_bytes()).unwrap();
    write!(file, "\n").unwrap();
}

fn analyze_file(
    file_name: &PathBuf,
    defs: &Defs,
    file_analysis: &data::Analysis,
    src_dir: &Path,
    output_dir: &Path,
) {
    let file = match file_name.strip_prefix(src_dir) {
        Ok(f) => f,
        Err(..) => {
            eprintln!("File not in the source directory: {}", file_name.display());
            return;
        }
    };

    let output_file = output_dir.join(file);
    let mut output_dir = output_file.clone();
    output_dir.pop();
    if let Err(err) = fs::create_dir_all(output_dir) {
        eprintln!(
            "Couldn't create dir for: {}, {:?}",
            output_file.display(),
            err
        );
        return;
    }
    let mut file = match File::create(&output_file) {
        Ok(f) => f,
        Err(err) => {
            eprintln!(
                "Couldn't open output file: {}, {:?}",
                output_file.display(),
                err
            );
            return;
        }
    };

    for import in &file_analysis.imports {
        let id = match import.ref_id {
            Some(id) => id,
            None => {
                eprintln!("Dropping import {}: {}, no ref", import.name, import.value);
                continue;
            }
        };

        let def = match defs.get(file_analysis, id) {
            Some(def) => def,
            None => {
                eprintln!("Dropping import {}: {}, no def for ref {:?}", import.name, import.value, id);
                continue;
            }
        };

        visit(&mut file, "use", &import.span, &def.qualname, None)
    }

    for def in &file_analysis.defs {
        let parent = def.parent
            .and_then(|parent_id| defs.get(file_analysis, parent_id).map(|d| d.qualname));

        let crate_name = &file_analysis.prelude.as_ref().unwrap().crate_id.name;
        let qualname = format!("{}{}", crate_name, def.qualname);
        visit(&mut file, "def", &def.span, &qualname, parent.as_ref().map(|p| &**p))
    }

    for ref_ in &file_analysis.refs {
        let def = match defs.get(file_analysis, ref_.ref_id) {
            Some(d) => d,
            None => {
                eprintln!("Dropping ref {:?}, kind {:?}, no def", ref_.ref_id, ref_.kind);
                continue;
            }
        };
        visit(
            &mut file,
            "use",
            &ref_.span,
            &def.qualname,
            /* context = */ None, // TODO
        )
    }
}

fn analyze_crate(
    analysis: &data::Analysis,
    defs: &Defs,
    src_dir: &Path,
    output_dir: &Path,
) {
    let mut per_file = HashMap::new();

    println!("Analyzing crate: {:?}", analysis.prelude);

    macro_rules! flat_map_per_file {
        ($field:ident) => {
            for item in &analysis.$field {
                let mut file_analysis =
                    per_file.entry(item.span.file_name.clone())
                        .or_insert_with(|| {
                            let prelude = analysis.prelude.clone();
                            let mut analysis = data::Analysis::new(analysis.config.clone());
                            analysis.prelude = prelude;
                            analysis
                        });
                file_analysis.$field.push(item.clone());
            }
        }
    }

    flat_map_per_file!(imports);
    flat_map_per_file!(defs);
    flat_map_per_file!(impls);
    flat_map_per_file!(refs);
    flat_map_per_file!(macro_refs);
    flat_map_per_file!(relations);

    for (mut name, analysis) in per_file.drain() {
        if name.is_relative() {
            name = src_dir.join(name);
        }
        analyze_file(&name, defs, &analysis, src_dir, output_dir);
    }
}

fn main() {
    let matches = app_from_crate!()
        .args_from_usage(
            "<src>    'Points to the source root'
             <input>  'Points to the deps/save-analysis directory'
             <output> 'Points to the directory where searchfox metadata should'",
        )
        .get_matches();

    let src_dir = Path::new(matches.value_of("src").unwrap());
    let input_dir = Path::new(matches.value_of("input").unwrap());
    let output_dir = Path::new(matches.value_of("output").unwrap());

    let loader = Loader::new(PathBuf::from(input_dir));

    let crates = rls_analysis::read_analysis_from_files(&loader, Default::default(), &[]);

    let mut defs = Defs::new();
    for krate in &crates {
        for def in &krate.analysis.defs {
            println!("Indexing def: {:?}", def);
            defs.insert(&krate.analysis, def);
        }
    }

    for krate in crates {
        analyze_crate(&krate.analysis, &defs, &src_dir, &output_dir);
    }
}
<|endoftext|>