<commit_before>
use call;
use error::GGRError;
use error::GGRResult;
use gron;
use serde_json;
use regex;
use std::collections::HashMap;
use entities;

pub struct Changes { }

impl Changes {
    /// Returns a ChangeInfos object on success. This value comes direct from the http call and
    /// is a valid json object
    pub fn query_changes(call: &call::Call, querystring: &str) -> GGRResult<ChangeInfos> {
        if let Ok(cr) = call.get("/changes/".into(), querystring) {
            let body = match cr.body {
                Some(x) => x,
                None => {
                    /* no body content */
                    return Ok(ChangeInfos::new());
                }
            };
            let data2 = try!(String::from_utf8(body));

            let data5 = match serde_json::de::from_str(&data2) {
                Ok(d) => d,
                Err(e) => {
                    println!("error: {}",e);
                    return Err(GGRError::from(e));
                }
            };

            let changeinfos = ChangeInfos::new_with_data(Some(data5));

            return Ok(changeinfos);
        } else {
            println!("call problem with: {}", &querystring);
        }
        Ok(ChangeInfos::new())
    }
}

/// Abstraction for Gron format into a Key/Val storage tyupe
#[derive(Debug)]
pub struct KeyValue {
    pub id: String,
    pub key: String,
    pub val: String,
}

impl From<String> for KeyValue {
    /// splits a string of 'a=b' style to `KeyValue { sel:"a", val:"b" }`
    fn from(s: String) -> Self {
        let mut out: KeyValue = KeyValue {
            id: String::new(),
            key: String::new(),
            val: String::new(),
        };

        let re = regex::Regex::new(r"^\[(?P<id>\di*?)].(?P<key>.*)=(?P<val>.*)$").unwrap();
        for cap in re.captures_iter(&s) {
            out.id = cap.name("id").unwrap_or("").trim().into();
            out.key = cap.name("key").unwrap_or("").trim().into();
            out.val = cap.name("val").unwrap_or("").trim().into();
        }

        out
    }
}

#[derive(Default, Debug)]
pub struct ChangeInfos {
    pub json: Option<serde_json::value::Value>,
    filter_key: Vec<String>,
    filter_val: Vec<String>,
}

impl ChangeInfos {
    /// creates a new ChangeInfos instance. ChangeInfos.json is None
    pub fn new() -> ChangeInfos {
        ChangeInfos {
            json: None,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// creates new ChangeInfos object with an initial ChangeInfos.json value
    pub fn new_with_data(json: Option<serde_json::value::Value>)
    -> ChangeInfos {
        ChangeInfos {
            json: json,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// returns the self.json as a array of KeyValue objects
    ///
    /// The returned array is filtered through `filter_key`, `filter_val` function
    pub fn as_keyval_array(&self) -> Vec<KeyValue> {
        let mut out = Vec::new();
        if let Some(json) = self.json.clone() {
            let mut vec = Vec::new();

            if let Err(x) = gron::json_to_gron(&mut vec, "", &json) {
                println!("error: {}", x);
                return Vec::new();
            };

            for line in vec.split(|x| *x == b'\n') {
                let kv = KeyValue::from(String::from_utf8_lossy(line).to_string());
                out.push(kv);

                // key filter
                /*
                for r in &self.filter_key {
                    if let Ok(re) = regex::Regex::new(r) {
                        if re.is_match(&kv.key) {
                            matched = true;
                            break;
                        }
                    }
                }

                // val filter
                for r in &self.filter_val {
                    if let Ok(re) = regex::Regex::new(r) {
                        if re.is_match(&kv.val) {
                            matched = true;
                            break;
                        }
                    }
                }

                if matched {
                */
                /*
                }
                */
            }
        }
        out
    }

    /// add a regular expression filter for keys
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_key(&mut self, r: &str) -> &mut Self {
        self.filter_key.push(String::from(r));
        self
    }

    /// add a regular expression filter for values
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_val(&mut self, r: String) -> &mut Self {
        self.filter_val.push(r);
        self
    }

    /// reset key and value filter
    pub fn filter_reset(&mut self) -> &mut Self {
        self.filter_val.clear();
        self.filter_key.clear();
        self
    }

    pub fn as_string_reg(&self, selector: &[String]) -> String {
        let vec = self.as_keyval_array();
        let mut out = String::from("");

        'next_kv: for kv in vec {
            for s in selector {
                if let Ok(re) = regex::Regex::new(s) {
                    if re.is_match(&kv.key) {
                        out.push_str(&format!("{}.{} {}\n", kv.id, kv.key, kv.val));
                        continue 'next_kv;
                    }
                }
            }
        }

        out
    }

    /// prints all selectable fields os a search string
    ///
    /// returns two values. First one is the count of returned json objects and second value is a
    /// HashMap<String, usize> with all fields and gow much they occure.
    pub fn fieldslist(&self) -> (usize, HashMap<String, usize>) {
        let mut out_hmap: HashMap<String, usize> = HashMap::new();
        let mut entries = 0;

        if let Some(obj) = self.json.clone() {
            if let Some(array) = obj.as_array() {
                entries = array.len();
                for entry in array {
                    match *entry {
                        serde_json::value::Value::Object(ref x) => {
                            for key in x.keys() {
                                let counter = out_hmap.entry(key.to_owned()).or_insert(0);
                                *counter += 1;
                            }
                        }
                        _ => continue,
                    }
                }
            } else {
                println!("no array");
            }
        }

        (entries, out_hmap)
    }

    /// return the string in machinereadable format
    pub fn raw(&self) -> String {
        let json = self.json.clone();

        format!("{}", json.unwrap_or(serde_json::value::Value::String("".into())))
    }

    /// return in human readable form
    pub fn human(&self) -> String {
        let json = self.json.clone();

        serde_json::ser::to_string_pretty(&json.unwrap_or_else(|| serde_json::value::Value::String("".into()))).unwrap_or("problem with pretty printing".into())
    }

    pub fn to_entities(&self) -> GGRResult<Vec<entities::ChangeInfo>> {
        let json = self.raw();

        match serde_json::de::from_str(&json) {
            Ok(decode) => { Ok(decode) },
            Err(r) => {
                println!("decode error: {}", r);
                Err(GGRError::from(r))
            },
        }
    }

    pub fn entity_from_commit(&self, commit: &str) -> GGRResult<entities::ChangeInfo> {
        let entities = try!(self.to_entities());

        for element in entities {
            if let Some(ref revisions) = element.revisions {
                for rev in revisions.keys() {
                    if *rev == commit {
                        return Ok(element.clone());
                    }
                }
            }
        }

        Err(GGRError::General("no entity found".into()))
    }

    /// returns a HashMap with project and tip of a topic.changeset
    pub fn project_tip(&self) -> GGRResult<HashMap<String, String>> {
        let entities = try!(self.to_entities());
        // find involved projects
        let mut list_of_projects = Vec::new();
        for element in &entities {
            let project = &element.project;
            if !list_of_projects.contains(project) {
                list_of_projects.push(project.clone());
            }
        }

        // find tip of every project
        let mut project_tip: HashMap<String, String> = HashMap::new();
        for project in list_of_projects {
            // find in entities the last change of every project for this topic
            let mut list_all_parents = Vec::new();
            for element in &entities {
                if let Some(ref cur_revision) = element.current_revision {
                    if let Some(ref revisions) = element.revisions {
                        if let Some(rev) = revisions.get(cur_revision) {
                            if let Some(ref commit) = rev.commit {
                                if let Some(ref parents) = commit.parents {
                                    for p in parents {
                                        list_all_parents.push(&p.commit);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            for element in &entities {
                if element.project == project {
                    if let Some(ref cur_revision) = element.current_revision {
                        if !list_all_parents.contains(&cur_revision) {
                            // a tip commit is never a parent for a topic
                            project_tip.insert(project, cur_revision.clone());
                            break;
                        }
                    }
                }
            }
        }

        Ok(project_tip)
    }
}

<commit_msg>changes: remove 'vim inserts i' from regular expression<commit_after>
use call;
use error::GGRError;
use error::GGRResult;
use gron;
use serde_json;
use regex;
use std::collections::HashMap;
use entities;

pub struct Changes { }

impl Changes {
    /// Returns a ChangeInfos object on success. This value comes direct from the http call and
    /// is a valid json object
    pub fn query_changes(call: &call::Call, querystring: &str) -> GGRResult<ChangeInfos> {
        if let Ok(cr) = call.get("/changes/".into(), querystring) {
            let body = match cr.body {
                Some(x) => x,
                None => {
                    /* no body content */
                    return Ok(ChangeInfos::new());
                }
            };
            let data2 = try!(String::from_utf8(body));

            let data5 = match serde_json::de::from_str(&data2) {
                Ok(d) => d,
                Err(e) => {
                    println!("error: {}",e);
                    return Err(GGRError::from(e));
                }
            };

            let changeinfos = ChangeInfos::new_with_data(Some(data5));

            return Ok(changeinfos);
        } else {
            println!("call problem with: {}", &querystring);
        }
        Ok(ChangeInfos::new())
    }
}

/// Abstraction for Gron format into a Key/Val storage tyupe
#[derive(Debug)]
pub struct KeyValue {
    pub id: String,
    pub key: String,
    pub val: String,
}

impl From<String> for KeyValue {
    /// splits a string of 'a=b' style to `KeyValue { sel:"a", val:"b" }`
    fn from(s: String) -> Self {
        let mut out: KeyValue = KeyValue {
            id: String::new(),
            key: String::new(),
            val: String::new(),
        };

        let re = regex::Regex::new(r"^\[(?P<id>\d*?)].(?P<key>.*)=(?P<val>.*)$").unwrap();
        for cap in re.captures_iter(&s) {
            out.id = cap.name("id").unwrap_or("").trim().into();
            out.key = cap.name("key").unwrap_or("").trim().into();
            out.val = cap.name("val").unwrap_or("").trim().into();
        }

        out
    }
}

#[derive(Default, Debug)]
pub struct ChangeInfos {
    pub json: Option<serde_json::value::Value>,
    filter_key: Vec<String>,
    filter_val: Vec<String>,
}

impl ChangeInfos {
    /// creates a new ChangeInfos instance. ChangeInfos.json is None
    pub fn new() -> ChangeInfos {
        ChangeInfos {
            json: None,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// creates new ChangeInfos object with an initial ChangeInfos.json value
    pub fn new_with_data(json: Option<serde_json::value::Value>)
    -> ChangeInfos {
        ChangeInfos {
            json: json,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// returns the self.json as a array of KeyValue objects
    ///
    /// The returned array is filtered through `filter_key`, `filter_val` function
    pub fn as_keyval_array(&self) -> Vec<KeyValue> {
        let mut out = Vec::new();
        if let Some(json) = self.json.clone() {
            let mut vec = Vec::new();

            if let Err(x) = gron::json_to_gron(&mut vec, "", &json) {
                println!("error: {}", x);
                return Vec::new();
            };

            for line in vec.split(|x| *x == b'\n') {
                let kv = KeyValue::from(String::from_utf8_lossy(line).to_string());
                out.push(kv);

                // key filter
                /*
                for r in &self.filter_key {
                    if let Ok(re) = regex::Regex::new(r) {
                        if re.is_match(&kv.key) {
                            matched = true;
                            break;
                        }
                    }
                }

                // val filter
                for r in &self.filter_val {
                    if let Ok(re) = regex::Regex::new(r) {
                        if re.is_match(&kv.val) {
                            matched = true;
                            break;
                        }
                    }
                }

                if matched {
                */
                /*
                }
                */
            }
        }
        out
    }

    /// add a regular expression filter for keys
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_key(&mut self, r: &str) -> &mut Self {
        self.filter_key.push(String::from(r));
        self
    }

    /// add a regular expression filter for values
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_val(&mut self, r: String) -> &mut Self {
        self.filter_val.push(r);
        self
    }

    /// reset key and value filter
    pub fn filter_reset(&mut self) -> &mut Self {
        self.filter_val.clear();
        self.filter_key.clear();
        self
    }

    pub fn as_string_reg(&self, selector: &[String]) -> String {
        let vec = self.as_keyval_array();
        let mut out = String::from("");

        'next_kv: for kv in vec {
            for s in selector {
                if let Ok(re) = regex::Regex::new(s) {
                    if re.is_match(&kv.key) {
                        out.push_str(&format!("{}.{} {}\n", kv.id, kv.key, kv.val));
                        continue 'next_kv;
                    }
                }
            }
        }

        out
    }

    /// prints all selectable fields os a search string
    ///
    /// returns two values. First one is the count of returned json objects and second value is a
    /// HashMap<String, usize> with all fields and gow much they occure.
    pub fn fieldslist(&self) -> (usize, HashMap<String, usize>) {
        let mut out_hmap: HashMap<String, usize> = HashMap::new();
        let mut entries = 0;

        if let Some(obj) = self.json.clone() {
            if let Some(array) = obj.as_array() {
                entries = array.len();
                for entry in array {
                    match *entry {
                        serde_json::value::Value::Object(ref x) => {
                            for key in x.keys() {
                                let counter = out_hmap.entry(key.to_owned()).or_insert(0);
                                *counter += 1;
                            }
                        }
                        _ => continue,
                    }
                }
            } else {
                println!("no array");
            }
        }

        (entries, out_hmap)
    }

    /// return the string in machinereadable format
    pub fn raw(&self) -> String {
        let json = self.json.clone();

        format!("{}", json.unwrap_or(serde_json::value::Value::String("".into())))
    }

    /// return in human readable form
    pub fn human(&self) -> String {
        let json = self.json.clone();

        serde_json::ser::to_string_pretty(&json.unwrap_or_else(|| serde_json::value::Value::String("".into()))).unwrap_or("problem with pretty printing".into())
    }

    pub fn to_entities(&self) -> GGRResult<Vec<entities::ChangeInfo>> {
        let json = self.raw();

        match serde_json::de::from_str(&json) {
            Ok(decode) => { Ok(decode) },
            Err(r) => {
                println!("decode error: {}", r);
                println!("json:\n{}", json);
                Err(GGRError::from(r))
            },
        }
    }

    pub fn entity_from_commit(&self, commit: &str) -> GGRResult<entities::ChangeInfo> {
        let entities = try!(self.to_entities());

        for element in entities {
            if let Some(ref revisions) = element.revisions {
                for rev in revisions.keys() {
                    if *rev == commit {
                        return Ok(element.clone());
                    }
                }
            }
        }

        Err(GGRError::General("no entity found".into()))
    }

    /// returns a HashMap with project and tip of a topic.changeset
    pub fn project_tip(&self) -> GGRResult<HashMap<String, String>> {
        let entities = try!(self.to_entities());
        // find involved projects
        let mut list_of_projects = Vec::new();
        for element in &entities {
            let project = &element.project;
            if !list_of_projects.contains(project) {
                list_of_projects.push(project.clone());
            }
        }

        // find tip of every project
        let mut project_tip: HashMap<String, String> = HashMap::new();
        for project in list_of_projects {
            // find in entities the last change of every project for this topic
            let mut list_all_parents = Vec::new();
            for element in &entities {
                if let Some(ref cur_revision) = element.current_revision {
                    if let Some(ref revisions) = element.revisions {
                        if let Some(rev) = revisions.get(cur_revision) {
                            if let Some(ref commit) = rev.commit {
                                if let Some(ref parents) = commit.parents {
                                    for p in parents {
                                        list_all_parents.push(&p.commit);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            for element in &entities {
                if element.project == project {
                    if let Some(ref cur_revision) = element.current_revision {
                        if !list_all_parents.contains(&cur_revision) {
                            // a tip commit is never a parent for a topic
                            project_tip.insert(project, cur_revision.clone());
                            break;
                        }
                    }
                }
            }
        }

        Ok(project_tip)
    }
}

<|endoftext|>


<commit_before>use core::convert::Infallible;
use std::time::Duration;

use embedded_hal::digital::blocking::{
    InputPin as InputPinHal, StatefulOutputPin as StatefulOutputPinHal,
    ToggleableOutputPin as ToggleableOutputPinHal,
};

use super::{InputPin, IoPin, OutputPin, Pin};
use crate::gpio::Mode;

const NANOS_PER_SEC: f64 = 1_000_000_000.0;

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for Pin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for InputPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for IoPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for OutputPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `StatefulOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::StatefulOutputPin for IoPin {
    fn is_set_high(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_high(self)
    }

    fn is_set_low(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_low(self)
    }
}

/// Unproven `StatefulOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::StatefulOutputPin for OutputPin {
    fn is_set_high(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_high(self)
    }

    fn is_set_low(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_low(self)
    }
}

/// Unproven `ToggleableOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::ToggleableOutputPin for IoPin {
    type Error = Infallible;

    fn toggle(&mut self) -> Result<(), Self::Error> {
        ToggleableOutputPinHal::toggle(self)
    }
}

/// Unproven `ToggleableOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::ToggleableOutputPin for OutputPin {
    type Error = Infallible;

    fn toggle(&mut self) -> Result<(), Self::Error> {
        ToggleableOutputPinHal::toggle(self)
    }
}

/// Unproven `Pwm` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::Pwm for OutputPin {
    type Duty = f64;
    type Channel = ();
    type Time = Duration;

    /// Disables a PWM `channel`.
    fn disable(&mut self, _channel: Self::Channel) {
        let _ = self.clear_pwm();
    }

    /// Enables a PWM `channel`.
    fn enable(&mut self, _channel: Self::Channel) {
        let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
    }

    /// Returns the current PWM period.
    fn get_period(&self) -> Self::Time {
        Duration::from_nanos(if self.frequency == 0.0 {
            0
        } else {
            ((1.0 / self.frequency) * NANOS_PER_SEC) as u64
        })
    }

    /// Returns the current duty cycle.
    fn get_duty(&self, _channel: Self::Channel) -> Self::Duty {
        self.duty_cycle
    }

    /// Returns the maximum duty cycle value.
    fn get_max_duty(&self) -> Self::Duty {
        1.0
    }

    /// Sets a new duty cycle.
    fn set_duty(&mut self, _channel: Self::Channel, duty: Self::Duty) {
        self.duty_cycle = duty.max(0.0).min(1.0);

        if self.soft_pwm.is_some() {
            let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
        }
    }

    /// Sets a new PWM period.
    fn set_period<P>(&mut self, period: P)
    where
        P: Into<Self::Time>,
    {
        let period = period.into();
        self.frequency =
            1.0 / (period.as_secs() as f64 + (f64::from(period.subsec_nanos()) / NANOS_PER_SEC));

        if self.soft_pwm.is_some() {
            let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
        }
    }
}

/// Unproven `Pwm` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::Pwm for IoPin {
    type Duty = f64;
    type Channel = ();
    type Time = Duration;

    /// Disables a PWM `channel`.
    fn disable(&mut self, _channel: Self::Channel) {
        let _ = self.clear_pwm();
    }

    /// Enables a PWM `channel`.
    fn enable(&mut self, _channel: Self::Channel) {
        let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
    }

    /// Returns the current PWM period.
    fn get_period(&self) -> Self::Time {
        Duration::from_nanos(if self.frequency == 0.0 {
            0
        } else {
            ((1.0 / self.frequency) * NANOS_PER_SEC) as u64
        })
    }

    /// Returns the current duty cycle.
    fn get_duty(&self, _channel: Self::Channel) -> Self::Duty {
        self.duty_cycle
    }

    /// Returns the maximum duty cycle value.
    fn get_max_duty(&self) -> Self::Duty {
        1.0
    }

    /// Sets a new duty cycle.
    fn set_duty(&mut self, _channel: Self::Channel, duty: Self::Duty) {
        self.duty_cycle = duty.max(0.0).min(1.0);

        if self.soft_pwm.is_some() {
            let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
        }
    }

    /// Sets a new PWM period.
    fn set_period<P>(&mut self, period: P)
    where
        P: Into<Self::Time>,
    {
        let period = period.into();
        self.frequency =
            1.0 / (period.as_secs() as f64 + (f64::from(period.subsec_nanos()) / NANOS_PER_SEC));

        if self.soft_pwm.is_some() {
            let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
        }
    }
}

/// Unproven `IoPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::IoPin<IoPin, IoPin> for IoPin {
    type Error = Infallible;

    /// Tries to convert this pin to input mode.
    ///
    /// If the pin is already in input mode, this method should succeed.
    fn into_input_pin(mut self) -> Result<IoPin, Self::Error> {
        if self.mode() != Mode::Input {
            self.set_mode(Mode::Input);
        }

        Ok(self)
    }

    /// Tries to convert this pin to output mode with the given initial state.
    ///
    /// If the pin is already in the requested state, this method should
    /// succeed.
    fn into_output_pin(
        mut self,
        state: embedded_hal_0::digital::v2::PinState,
    ) -> Result<IoPin, Self::Error> {
        match state {
            embedded_hal_0::digital::v2::PinState::Low => self.set_low(),
            embedded_hal_0::digital::v2::PinState::High => self.set_high(),
        }

        if self.mode() != Mode::Output {
            self.set_mode(Mode::Output);
        }

        Ok(self)
    }
}
<commit_msg>Fix error in unproven HAL traits for v0.2.7<commit_after>use core::convert::Infallible;
use std::time::Duration;

use embedded_hal::digital::{
    InputPin as InputPinHal, StatefulOutputPin as StatefulOutputPinHal,
    ToggleableOutputPin as ToggleableOutputPinHal,
};

use super::{InputPin, IoPin, OutputPin, Pin};
use crate::gpio::Mode;

const NANOS_PER_SEC: f64 = 1_000_000_000.0;

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for Pin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for InputPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for IoPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for OutputPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `StatefulOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::StatefulOutputPin for IoPin {
    fn is_set_high(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_high(self)
    }

    fn is_set_low(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_low(self)
    }
}

/// Unproven `StatefulOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::StatefulOutputPin for OutputPin {
    fn is_set_high(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_high(self)
    }

    fn is_set_low(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_low(self)
    }
}

/// Unproven `ToggleableOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::ToggleableOutputPin for IoPin {
    type Error = Infallible;

    fn toggle(&mut self) -> Result<(), Self::Error> {
        ToggleableOutputPinHal::toggle(self)
    }
}

/// Unproven `ToggleableOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::ToggleableOutputPin for OutputPin {
    type Error = Infallible;

    fn toggle(&mut self) -> Result<(), Self::Error> {
        ToggleableOutputPinHal::toggle(self)
    }
}

/// Unproven `Pwm` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::Pwm for OutputPin {
    type Duty = f64;
    type Channel = ();
    type Time = Duration;

    /// Disables a PWM `channel`.
    fn disable(&mut self, _channel: Self::Channel) {
        let _ = self.clear_pwm();
    }

    /// Enables a PWM `channel`.
    fn enable(&mut self, _channel: Self::Channel) {
        let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
    }

    /// Returns the current PWM period.
    fn get_period(&self) -> Self::Time {
        Duration::from_nanos(if self.frequency == 0.0 {
            0
        } else {
            ((1.0 / self.frequency) * NANOS_PER_SEC) as u64
        })
    }

    /// Returns the current duty cycle.
    fn get_duty(&self, _channel: Self::Channel) -> Self::Duty {
        self.duty_cycle
    }

    /// Returns the maximum duty cycle value.
    fn get_max_duty(&self) -> Self::Duty {
        1.0
    }

    /// Sets a new duty cycle.
    fn set_duty(&mut self, _channel: Self::Channel, duty: Self::Duty) {
        self.duty_cycle = duty.max(0.0).min(1.0);

        if self.soft_pwm.is_some() {
            let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
        }
    }

    /// Sets a new PWM period.
    fn set_period<P>(&mut self, period: P)
    where
        P: Into<Self::Time>,
    {
        let period = period.into();
        self.frequency =
            1.0 / (period.as_secs() as f64 + (f64::from(period.subsec_nanos()) / NANOS_PER_SEC));

        if self.soft_pwm.is_some() {
            let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
        }
    }
}

/// Unproven `Pwm` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::Pwm for IoPin {
    type Duty = f64;
    type Channel = ();
    type Time = Duration;

    /// Disables a PWM `channel`.
    fn disable(&mut self, _channel: Self::Channel) {
        let _ = self.clear_pwm();
    }

    /// Enables a PWM `channel`.
    fn enable(&mut self, _channel: Self::Channel) {
        let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
    }

    /// Returns the current PWM period.
    fn get_period(&self) -> Self::Time {
        Duration::from_nanos(if self.frequency == 0.0 {
            0
        } else {
            ((1.0 / self.frequency) * NANOS_PER_SEC) as u64
        })
    }

    /// Returns the current duty cycle.
    fn get_duty(&self, _channel: Self::Channel) -> Self::Duty {
        self.duty_cycle
    }

    /// Returns the maximum duty cycle value.
    fn get_max_duty(&self) -> Self::Duty {
        1.0
    }

    /// Sets a new duty cycle.
    fn set_duty(&mut self, _channel: Self::Channel, duty: Self::Duty) {
        self.duty_cycle = duty.max(0.0).min(1.0);

        if self.soft_pwm.is_some() {
            let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
        }
    }

    /// Sets a new PWM period.
    fn set_period<P>(&mut self, period: P)
    where
        P: Into<Self::Time>,
    {
        let period = period.into();
        self.frequency =
            1.0 / (period.as_secs() as f64 + (f64::from(period.subsec_nanos()) / NANOS_PER_SEC));

        if self.soft_pwm.is_some() {
            let _ = self.set_pwm_frequency(self.frequency, self.duty_cycle);
        }
    }
}

/// Unproven `IoPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::IoPin<IoPin, IoPin> for IoPin {
    type Error = Infallible;

    /// Tries to convert this pin to input mode.
    ///
    /// If the pin is already in input mode, this method should succeed.
    fn into_input_pin(mut self) -> Result<IoPin, Self::Error> {
        if self.mode() != Mode::Input {
            self.set_mode(Mode::Input);
        }

        Ok(self)
    }

    /// Tries to convert this pin to output mode with the given initial state.
    ///
    /// If the pin is already in the requested state, this method should
    /// succeed.
    fn into_output_pin(
        mut self,
        state: embedded_hal_0::digital::v2::PinState,
    ) -> Result<IoPin, Self::Error> {
        match state {
            embedded_hal_0::digital::v2::PinState::Low => self.set_low(),
            embedded_hal_0::digital::v2::PinState::High => self.set_high(),
        }

        if self.mode() != Mode::Output {
            self.set_mode(Mode::Output);
        }

        Ok(self)
    }
}
<|endoftext|>


<commit_before>use super::super::format_field::FormatField;
use super::super::formatter::{get_it_at, warn_incomplete_conv, Base, FormatPrimitive, InPrefix};
use super::base_conv;
use super::base_conv::RadixDef;

// if the memory, copy, and comparison cost of chars
//  becomes an issue, we can always operate in vec<u8> here
//  rather than just at de_hex

pub struct FloatAnalysis {
    pub len_important: usize,
    // none means no decimal point.
    pub decimal_pos: Option<usize>,
    pub follow: Option<char>,
}
fn has_enough_digits(
    hex_input: bool,
    hex_output: bool,
    string_position: usize,
    starting_position: usize,
    limit: usize,
) -> bool {
    // -1s are for rounding
    if hex_output {
        if hex_input {
            ((string_position - 1) - starting_position >= limit)
        } else {
            false //undecidable without converting
        }
    } else if hex_input {
        ((((string_position - 1) - starting_position) * 9) / 8 >= limit)
    } else {
        ((string_position - 1) - starting_position >= limit)
    }
}

impl FloatAnalysis {
    pub fn analyze(
        str_in: &str,
        inprefix: &InPrefix,
        max_sd_opt: Option<usize>,
        max_after_dec_opt: Option<usize>,
        hex_output: bool,
    ) -> FloatAnalysis {
        // this fn assumes
        // the input string
        // has no leading spaces or 0s
        let str_it = get_it_at(inprefix.offset, str_in);
        let mut ret = FloatAnalysis {
            len_important: 0,
            decimal_pos: None,
            follow: None,
        };
        let hex_input = match inprefix.radix_in {
            Base::Hex => true,
            Base::Ten => false,
            Base::Octal => {
                panic!("this should never happen: floats should never receive octal input");
            }
        };
        let mut i = 0;
        let mut pos_before_first_nonzero_after_decimal: Option<usize> = None;
        for c in str_it {
            match c {
                e @ '0'..='9' | e @ 'A'..='F' | e @ 'a'..='f' => {
                    if !hex_input {
                        match e {
                            '0'..='9' => {}
                            _ => {
                                warn_incomplete_conv(str_in);
                                break;
                            }
                        }
                    }
                    if ret.decimal_pos.is_some()
                        && pos_before_first_nonzero_after_decimal.is_none()
                        && e != '0'
                    {
                        pos_before_first_nonzero_after_decimal = Some(i - 1);
                    }
                    if let Some(max_sd) = max_sd_opt {
                        if i == max_sd {
                            // follow is used in cases of %g
                            // where the character right after the last
                            // sd is considered is rounded affecting
                            // the previous digit in 1/2 of instances
                            ret.follow = Some(e);
                        } else if ret.decimal_pos.is_some() && i > max_sd {
                            break;
                        }
                    }
                    if let Some(max_after_dec) = max_after_dec_opt {
                        if let Some(p) = ret.decimal_pos {
                            if has_enough_digits(hex_input, hex_output, i, p, max_after_dec) {
                                break;
                            }
                        }
                    } else if let Some(max_sd) = max_sd_opt {
                        if let Some(p) = pos_before_first_nonzero_after_decimal {
                            if has_enough_digits(hex_input, hex_output, i, p, max_sd) {
                                break;
                            }
                        }
                    }
                }
                '.' => {
                    if ret.decimal_pos.is_none() {
                        ret.decimal_pos = Some(i);
                    } else {
                        warn_incomplete_conv(str_in);
                        break;
                    }
                }
                _ => {
                    warn_incomplete_conv(str_in);
                    break;
                }
            };
            i += 1;
        }
        ret.len_important = i;
        ret
    }
}

fn de_hex(src: &str, before_decimal: bool) -> String {
    let rten = base_conv::RadixTen;
    let rhex = base_conv::RadixHex;
    if before_decimal {
        base_conv::base_conv_str(src, &rhex, &rten)
    } else {
        let as_arrnum_hex = base_conv::str_to_arrnum(src, &rhex);
        let s = format!(
            "{}",
            base_conv::base_conv_float(&as_arrnum_hex, rhex.get_max(), rten.get_max())
        );
        if s.len() > 2 {
            String::from(&s[2..])
        } else {
            // zero
            s
        }
    }
}

// takes a string in,
// truncates to a position,
// bumps the last digit up one,
// and if the digit was nine
// propagate to the next, etc.
fn _round_str_from(in_str: &str, position: usize) -> (String, bool) {
    let mut it = in_str[0..position].chars();
    let mut rev = String::new();
    let mut i = position;
    let mut finished_in_dec = false;
    while let Some(c) = it.next_back() {
        i -= 1;
        match c {
            '9' => {
                rev.push('0');
            }
            e => {
                rev.push(((e as u8) + 1) as char);
                finished_in_dec = true;
                break;
            }
        }
    }
    let mut fwd = String::from(&in_str[0..i]);
    for ch in rev.chars().rev() {
        fwd.push(ch);
    }
    (fwd, finished_in_dec)
}

fn round_terminal_digit(
    before_dec: String,
    after_dec: String,
    position: usize,
) -> (String, String) {
    if position < after_dec.len() {
        let digit_at_pos: char;
        {
            digit_at_pos = (&after_dec[position..=position]).chars().next().expect("");
        }
        if let '5'..='9' = digit_at_pos {
            let (new_after_dec, finished_in_dec) = _round_str_from(&after_dec, position);
            if finished_in_dec {
                return (before_dec, new_after_dec);
            } else {
                let (new_before_dec, _) = _round_str_from(&before_dec, before_dec.len());
                return (new_before_dec, new_after_dec);
            }
            // TODO
        }
    }
    (before_dec, after_dec)
}

pub fn get_primitive_dec(
    inprefix: &InPrefix,
    str_in: &str,
    analysis: &FloatAnalysis,
    last_dec_place: usize,
    sci_mode: Option<bool>,
) -> FormatPrimitive {
    let mut f: FormatPrimitive = Default::default();

    // add negative sign section
    if inprefix.sign == -1 {
        f.prefix = Some(String::from("-"));
    }

    // assign the digits before and after the decimal points
    // to separate slices. If no digits after decimal point,
    // assign 0
    let (mut first_segment_raw, second_segment_raw) = match analysis.decimal_pos {
        Some(pos) => (&str_in[..pos], &str_in[pos + 1..]),
        None => (&str_in[..], "0"),
    };
    if first_segment_raw.is_empty() {
        first_segment_raw = "0";
    }
    // convert to string, de_hexifying if input is in hex.
    let (first_segment, second_segment) = match inprefix.radix_in {
        Base::Hex => (
            de_hex(first_segment_raw, true),
            de_hex(second_segment_raw, false),
        ),
        _ => (
            String::from(first_segment_raw),
            String::from(second_segment_raw),
        ),
    };
    let (pre_dec_unrounded, post_dec_unrounded, mantissa) = if sci_mode.is_some() {
        if first_segment.len() > 1 {
            let mut post_dec = String::from(&first_segment[1..]);
            post_dec.push_str(&second_segment);
            (
                String::from(&first_segment[0..1]),
                post_dec,
                first_segment.len() as isize - 1,
            )
        } else {
            match first_segment.chars().next() {
                Some('0') => {
                    let it = second_segment.chars().enumerate();
                    let mut m: isize = 0;
                    let mut pre = String::from("0");
                    let mut post = String::from("0");
                    for (i, c) in it {
                        match c {
                            '0' => {}
                            _ => {
                                m = -((i as isize) + 1);
                                pre = String::from(&second_segment[i..=i]);
                                post = String::from(&second_segment[i + 1..]);
                                break;
                            }
                        }
                    }
                    (pre, post, m)
                }
                Some(_) => (first_segment, second_segment, 0),
                None => {
                    panic!("float_common: no chars in first segment.");
                }
            }
        }
    } else {
        (first_segment, second_segment, 0)
    };

    let (pre_dec_draft, post_dec_draft) =
        round_terminal_digit(pre_dec_unrounded, post_dec_unrounded, last_dec_place - 1);

    f.pre_decimal = Some(pre_dec_draft);
    f.post_decimal = Some(post_dec_draft);
    if let Some(capitalized) = sci_mode {
        let si_ind = if capitalized { 'E' } else { 'e' };
        f.suffix = Some(if mantissa >= 0 {
            format!("{}+{:02}", si_ind, mantissa)
        } else {
            // negative sign is considered in format!s
            // leading zeroes
            format!("{}{:03}", si_ind, mantissa)
        });
    }

    f
}

pub fn primitive_to_str_common(prim: &FormatPrimitive, field: &FormatField) -> String {
    let mut final_str = String::new();
    if let Some(ref prefix) = prim.prefix {
        final_str.push_str(&prefix);
    }
    match prim.pre_decimal {
        Some(ref pre_decimal) => {
            final_str.push_str(&pre_decimal);
        }
        None => {
            panic!(
                "error, format primitives provided to int, will, incidentally under correct \
                 behavior, always have a pre_dec value."
            );
        }
    }
    let decimal_places = field.second_field.unwrap_or(6);
    match prim.post_decimal {
        Some(ref post_decimal) => {
            if !post_decimal.is_empty() && decimal_places > 0 {
                final_str.push('.');
                let len_avail = post_decimal.len() as u32;

                if decimal_places >= len_avail {
                    // println!("dec {}, len avail {}", decimal_places, len_avail);
                    final_str.push_str(post_decimal);

                    if *field.field_char != 'g' && *field.field_char != 'G' {
                        let diff = decimal_places - len_avail;
                        for _ in 0..diff {
                            final_str.push('0');
                        }
                    }
                } else {
                    // println!("printing to only {}", decimal_places);
                    final_str.push_str(&post_decimal[0..decimal_places as usize]);
                }
            }
        }
        None => {
            panic!(
                "error, format primitives provided to int, will, incidentally under correct \
                 behavior, always have a pre_dec value."
            );
        }
    }
    if let Some(ref suffix) = prim.suffix {
        final_str.push_str(suffix);
    }

    final_str
}
<commit_msg>refactor/polish ~ fix `cargo clippy` complaints (unused_parens)<commit_after>use super::super::format_field::FormatField;
use super::super::formatter::{get_it_at, warn_incomplete_conv, Base, FormatPrimitive, InPrefix};
use super::base_conv;
use super::base_conv::RadixDef;

// if the memory, copy, and comparison cost of chars
//  becomes an issue, we can always operate in vec<u8> here
//  rather than just at de_hex

pub struct FloatAnalysis {
    pub len_important: usize,
    // none means no decimal point.
    pub decimal_pos: Option<usize>,
    pub follow: Option<char>,
}
fn has_enough_digits(
    hex_input: bool,
    hex_output: bool,
    string_position: usize,
    starting_position: usize,
    limit: usize,
) -> bool {
    // -1s are for rounding
    if hex_output {
        if hex_input {
            (string_position - 1) - starting_position >= limit
        } else {
            false //undecidable without converting
        }
    } else if hex_input {
        (((string_position - 1) - starting_position) * 9) / 8 >= limit
    } else {
        (string_position - 1) - starting_position >= limit
    }
}

impl FloatAnalysis {
    pub fn analyze(
        str_in: &str,
        inprefix: &InPrefix,
        max_sd_opt: Option<usize>,
        max_after_dec_opt: Option<usize>,
        hex_output: bool,
    ) -> FloatAnalysis {
        // this fn assumes
        // the input string
        // has no leading spaces or 0s
        let str_it = get_it_at(inprefix.offset, str_in);
        let mut ret = FloatAnalysis {
            len_important: 0,
            decimal_pos: None,
            follow: None,
        };
        let hex_input = match inprefix.radix_in {
            Base::Hex => true,
            Base::Ten => false,
            Base::Octal => {
                panic!("this should never happen: floats should never receive octal input");
            }
        };
        let mut i = 0;
        let mut pos_before_first_nonzero_after_decimal: Option<usize> = None;
        for c in str_it {
            match c {
                e @ '0'..='9' | e @ 'A'..='F' | e @ 'a'..='f' => {
                    if !hex_input {
                        match e {
                            '0'..='9' => {}
                            _ => {
                                warn_incomplete_conv(str_in);
                                break;
                            }
                        }
                    }
                    if ret.decimal_pos.is_some()
                        && pos_before_first_nonzero_after_decimal.is_none()
                        && e != '0'
                    {
                        pos_before_first_nonzero_after_decimal = Some(i - 1);
                    }
                    if let Some(max_sd) = max_sd_opt {
                        if i == max_sd {
                            // follow is used in cases of %g
                            // where the character right after the last
                            // sd is considered is rounded affecting
                            // the previous digit in 1/2 of instances
                            ret.follow = Some(e);
                        } else if ret.decimal_pos.is_some() && i > max_sd {
                            break;
                        }
                    }
                    if let Some(max_after_dec) = max_after_dec_opt {
                        if let Some(p) = ret.decimal_pos {
                            if has_enough_digits(hex_input, hex_output, i, p, max_after_dec) {
                                break;
                            }
                        }
                    } else if let Some(max_sd) = max_sd_opt {
                        if let Some(p) = pos_before_first_nonzero_after_decimal {
                            if has_enough_digits(hex_input, hex_output, i, p, max_sd) {
                                break;
                            }
                        }
                    }
                }
                '.' => {
                    if ret.decimal_pos.is_none() {
                        ret.decimal_pos = Some(i);
                    } else {
                        warn_incomplete_conv(str_in);
                        break;
                    }
                }
                _ => {
                    warn_incomplete_conv(str_in);
                    break;
                }
            };
            i += 1;
        }
        ret.len_important = i;
        ret
    }
}

fn de_hex(src: &str, before_decimal: bool) -> String {
    let rten = base_conv::RadixTen;
    let rhex = base_conv::RadixHex;
    if before_decimal {
        base_conv::base_conv_str(src, &rhex, &rten)
    } else {
        let as_arrnum_hex = base_conv::str_to_arrnum(src, &rhex);
        let s = format!(
            "{}",
            base_conv::base_conv_float(&as_arrnum_hex, rhex.get_max(), rten.get_max())
        );
        if s.len() > 2 {
            String::from(&s[2..])
        } else {
            // zero
            s
        }
    }
}

// takes a string in,
// truncates to a position,
// bumps the last digit up one,
// and if the digit was nine
// propagate to the next, etc.
fn _round_str_from(in_str: &str, position: usize) -> (String, bool) {
    let mut it = in_str[0..position].chars();
    let mut rev = String::new();
    let mut i = position;
    let mut finished_in_dec = false;
    while let Some(c) = it.next_back() {
        i -= 1;
        match c {
            '9' => {
                rev.push('0');
            }
            e => {
                rev.push(((e as u8) + 1) as char);
                finished_in_dec = true;
                break;
            }
        }
    }
    let mut fwd = String::from(&in_str[0..i]);
    for ch in rev.chars().rev() {
        fwd.push(ch);
    }
    (fwd, finished_in_dec)
}

fn round_terminal_digit(
    before_dec: String,
    after_dec: String,
    position: usize,
) -> (String, String) {
    if position < after_dec.len() {
        let digit_at_pos: char;
        {
            digit_at_pos = (&after_dec[position..=position]).chars().next().expect("");
        }
        if let '5'..='9' = digit_at_pos {
            let (new_after_dec, finished_in_dec) = _round_str_from(&after_dec, position);
            if finished_in_dec {
                return (before_dec, new_after_dec);
            } else {
                let (new_before_dec, _) = _round_str_from(&before_dec, before_dec.len());
                return (new_before_dec, new_after_dec);
            }
            // TODO
        }
    }
    (before_dec, after_dec)
}

pub fn get_primitive_dec(
    inprefix: &InPrefix,
    str_in: &str,
    analysis: &FloatAnalysis,
    last_dec_place: usize,
    sci_mode: Option<bool>,
) -> FormatPrimitive {
    let mut f: FormatPrimitive = Default::default();

    // add negative sign section
    if inprefix.sign == -1 {
        f.prefix = Some(String::from("-"));
    }

    // assign the digits before and after the decimal points
    // to separate slices. If no digits after decimal point,
    // assign 0
    let (mut first_segment_raw, second_segment_raw) = match analysis.decimal_pos {
        Some(pos) => (&str_in[..pos], &str_in[pos + 1..]),
        None => (&str_in[..], "0"),
    };
    if first_segment_raw.is_empty() {
        first_segment_raw = "0";
    }
    // convert to string, de_hexifying if input is in hex.
    let (first_segment, second_segment) = match inprefix.radix_in {
        Base::Hex => (
            de_hex(first_segment_raw, true),
            de_hex(second_segment_raw, false),
        ),
        _ => (
            String::from(first_segment_raw),
            String::from(second_segment_raw),
        ),
    };
    let (pre_dec_unrounded, post_dec_unrounded, mantissa) = if sci_mode.is_some() {
        if first_segment.len() > 1 {
            let mut post_dec = String::from(&first_segment[1..]);
            post_dec.push_str(&second_segment);
            (
                String::from(&first_segment[0..1]),
                post_dec,
                first_segment.len() as isize - 1,
            )
        } else {
            match first_segment.chars().next() {
                Some('0') => {
                    let it = second_segment.chars().enumerate();
                    let mut m: isize = 0;
                    let mut pre = String::from("0");
                    let mut post = String::from("0");
                    for (i, c) in it {
                        match c {
                            '0' => {}
                            _ => {
                                m = -((i as isize) + 1);
                                pre = String::from(&second_segment[i..=i]);
                                post = String::from(&second_segment[i + 1..]);
                                break;
                            }
                        }
                    }
                    (pre, post, m)
                }
                Some(_) => (first_segment, second_segment, 0),
                None => {
                    panic!("float_common: no chars in first segment.");
                }
            }
        }
    } else {
        (first_segment, second_segment, 0)
    };

    let (pre_dec_draft, post_dec_draft) =
        round_terminal_digit(pre_dec_unrounded, post_dec_unrounded, last_dec_place - 1);

    f.pre_decimal = Some(pre_dec_draft);
    f.post_decimal = Some(post_dec_draft);
    if let Some(capitalized) = sci_mode {
        let si_ind = if capitalized { 'E' } else { 'e' };
        f.suffix = Some(if mantissa >= 0 {
            format!("{}+{:02}", si_ind, mantissa)
        } else {
            // negative sign is considered in format!s
            // leading zeroes
            format!("{}{:03}", si_ind, mantissa)
        });
    }

    f
}

pub fn primitive_to_str_common(prim: &FormatPrimitive, field: &FormatField) -> String {
    let mut final_str = String::new();
    if let Some(ref prefix) = prim.prefix {
        final_str.push_str(&prefix);
    }
    match prim.pre_decimal {
        Some(ref pre_decimal) => {
            final_str.push_str(&pre_decimal);
        }
        None => {
            panic!(
                "error, format primitives provided to int, will, incidentally under correct \
                 behavior, always have a pre_dec value."
            );
        }
    }
    let decimal_places = field.second_field.unwrap_or(6);
    match prim.post_decimal {
        Some(ref post_decimal) => {
            if !post_decimal.is_empty() && decimal_places > 0 {
                final_str.push('.');
                let len_avail = post_decimal.len() as u32;

                if decimal_places >= len_avail {
                    // println!("dec {}, len avail {}", decimal_places, len_avail);
                    final_str.push_str(post_decimal);

                    if *field.field_char != 'g' && *field.field_char != 'G' {
                        let diff = decimal_places - len_avail;
                        for _ in 0..diff {
                            final_str.push('0');
                        }
                    }
                } else {
                    // println!("printing to only {}", decimal_places);
                    final_str.push_str(&post_decimal[0..decimal_places as usize]);
                }
            }
        }
        None => {
            panic!(
                "error, format primitives provided to int, will, incidentally under correct \
                 behavior, always have a pre_dec value."
            );
        }
    }
    if let Some(ref suffix) = prim.suffix {
        final_str.push_str(suffix);
    }

    final_str
}
<|endoftext|>


<commit_before>#![feature(custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec<String>) {
    let in_rustc_test_suite = rustc_test_suite().is_some();
    // Add some flags we always want.
    flags.push("--edition 2018".to_owned());
    if in_rustc_test_suite {
        // Less aggressive warnings to make the rustc toolstate management less painful.
        // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
        flags.push("-Astable-features".to_owned());
    } else {
        flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    }
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        flags.push(format!("--sysroot {}", sysroot));
    }

    // The rest of the configuration.
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if in_rustc_test_suite {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        // Optimizing too aggressivley makes UB detection harder, but test at least
        // the default value.
        // FIXME: Opt level 3 ICEs during stack trace generation.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    run_tests("compile-fail", path, target, flags);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    run_tests("ui", path, target, flags);
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
}

fn test_runner(_tests: &[&()]) {
    // Add a test env var to do environment communication tests
    std::env::set_var("MIRI_ENV_VAR_TEST", "0");

    run_pass_miri(false);
    run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<commit_msg>update comment re: not using higher mir-opt-level<commit_after>#![feature(custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec<String>) {
    let in_rustc_test_suite = rustc_test_suite().is_some();
    // Add some flags we always want.
    flags.push("--edition 2018".to_owned());
    if in_rustc_test_suite {
        // Less aggressive warnings to make the rustc toolstate management less painful.
        // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
        flags.push("-Astable-features".to_owned());
    } else {
        flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    }
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        flags.push(format!("--sysroot {}", sysroot));
    }

    // The rest of the configuration.
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if in_rustc_test_suite {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        // FIXME: Opt level 2 ICEs during stack trace generation.
        // See https://github.com/rust-lang/rust/issues/66077.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    run_tests("compile-fail", path, target, flags);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    run_tests("ui", path, target, flags);
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
}

fn test_runner(_tests: &[&()]) {
    // Add a test env var to do environment communication tests
    std::env::set_var("MIRI_ENV_VAR_TEST", "0");

    run_pass_miri(false);
    run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<|endoftext|>


<commit_before>//! A higher level attributes based on TokenTree, with also some shortcuts.

use std::{ops, sync::Arc};

use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{hygiene::Hygiene, AstId, InFile};
use mbe::ast_to_token_tree;
use syntax::{
    ast::{self, AstNode, AttrsOwner},
    SmolStr,
};
use tt::Subtree;

use crate::{
    db::DefDatabase,
    item_tree::{ItemTreeId, ItemTreeNode},
    nameres::ModuleSource,
    path::ModPath,
    src::HasChildSource,
    AdtId, AttrDefId, Lookup,
};

#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Attrs {
    entries: Option<Arc<[Attr]>>,
}

impl ops::Deref for Attrs {
    type Target = [Attr];

    fn deref(&self) -> &[Attr] {
        match &self.entries {
            Some(it) => &*it,
            None => &[],
        }
    }
}

impl Attrs {
    pub const EMPTY: Attrs = Attrs { entries: None };

    pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
        match def {
            AttrDefId::ModuleId(module) => {
                let def_map = db.crate_def_map(module.krate);
                let mod_data = &def_map[module.local_id];
                match mod_data.declaration_source(db) {
                    Some(it) => {
                        Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner))
                    }
                    None => Attrs::from_attrs_owner(
                        db,
                        mod_data.definition_source(db).as_ref().map(|src| match src {
                            ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
                            ModuleSource::Module(module) => module as &dyn AttrsOwner,
                        }),
                    ),
                }
            }
            AttrDefId::FieldId(it) => {
                let src = it.parent.child_source(db);
                match &src.value[it.local_id] {
                    Either::Left(_tuple) => Attrs::default(),
                    Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
                }
            }
            AttrDefId::EnumVariantId(var_id) => {
                let src = var_id.parent.child_source(db);
                let src = src.as_ref().map(|it| &it[var_id.local_id]);
                Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
            }
            AttrDefId::AdtId(it) => match it {
                AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
                AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
                AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            },
            AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::MacroDefId(it) => {
                it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
            }
            AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
        }
    }

    pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs {
        let hygiene = Hygiene::new(db.upcast(), owner.file_id);
        Attrs::new(owner.value, &hygiene)
    }

    pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
        let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map(
            |docs_text| Attr {
                input: Some(AttrInput::Literal(SmolStr::new(docs_text))),
                path: ModPath::from(hir_expand::name!(doc)),
            },
        );
        let mut attrs = owner.attrs().peekable();
        let entries = if attrs.peek().is_none() {
            // Avoid heap allocation
            None
        } else {
            Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect())
        };
        Attrs { entries }
    }

    pub fn merge(&self, other: Attrs) -> Attrs {
        match (&self.entries, &other.entries) {
            (None, None) => Attrs { entries: None },
            (Some(entries), None) | (None, Some(entries)) => {
                Attrs { entries: Some(entries.clone()) }
            }
            (Some(a), Some(b)) => {
                Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
            }
        }
    }

    pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
        AttrQuery { attrs: self, key }
    }

    pub fn cfg(&self) -> impl Iterator<Item = CfgExpr> + '_ {
        // FIXME: handle cfg_attr :-)
        self.by_key("cfg").tt_values().map(CfgExpr::parse)
    }
    pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
        self.cfg().all(|cfg| cfg_options.check(&cfg) != Some(false))
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Attr {
    pub(crate) path: ModPath,
    pub(crate) input: Option<AttrInput>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttrInput {
    /// `#[attr = "string"]`
    Literal(SmolStr),
    /// `#[attr(subtree)]`
    TokenTree(Subtree),
}

impl Attr {
    fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
        let path = ModPath::from_src(ast.path()?, hygiene)?;
        let input = if let Some(lit) = ast.literal() {
            // FIXME: escape? raw string?
            let value = lit.syntax().first_token()?.text().trim_matches('"').into();
            Some(AttrInput::Literal(value))
        } else if let Some(tt) = ast.token_tree() {
            Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
        } else {
            None
        };
        Some(Attr { path, input })
    }
}

#[derive(Debug, Clone, Copy)]
pub struct AttrQuery<'a> {
    attrs: &'a Attrs,
    key: &'static str,
}

impl<'a> AttrQuery<'a> {
    /// For an attribute like `#[attr(value)]`, returns the `(value)` subtree.
    ///
    /// If the attribute does not have a token tree argument, returns `None`.
    pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
        self.attrs().filter_map(|attr| match attr.input.as_ref()? {
            AttrInput::TokenTree(it) => Some(it),
            _ => None,
        })
    }

    /// For an attribute like `#[key = "value"]`, returns `"value"`.
    ///
    /// Returns `None` if the attribute does not have `key = "value"` form.
    pub fn string_value(self) -> Option<&'a SmolStr> {
        self.attrs().find_map(|attr| match attr.input.as_ref()? {
            AttrInput::Literal(it) => Some(it),
            _ => None,
        })
    }

    pub fn exists(self) -> bool {
        self.attrs().next().is_some()
    }

    fn attrs(self) -> impl Iterator<Item = &'a Attr> {
        let key = self.key;
        self.attrs
            .iter()
            .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key))
    }
}

fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs
where
    N: ast::AttrsOwner,
{
    let src = InFile::new(src.file_id, src.to_node(db.upcast()));
    Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
}

fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs {
    let tree = db.item_tree(id.file_id);
    let mod_item = N::id_to_mod_item(id.value);
    tree.attrs(mod_item.into()).clone()
}
<commit_msg>Remove incorrect docs<commit_after>//! A higher level attributes based on TokenTree, with also some shortcuts.

use std::{ops, sync::Arc};

use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{hygiene::Hygiene, AstId, InFile};
use mbe::ast_to_token_tree;
use syntax::{
    ast::{self, AstNode, AttrsOwner},
    SmolStr,
};
use tt::Subtree;

use crate::{
    db::DefDatabase,
    item_tree::{ItemTreeId, ItemTreeNode},
    nameres::ModuleSource,
    path::ModPath,
    src::HasChildSource,
    AdtId, AttrDefId, Lookup,
};

#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Attrs {
    entries: Option<Arc<[Attr]>>,
}

impl ops::Deref for Attrs {
    type Target = [Attr];

    fn deref(&self) -> &[Attr] {
        match &self.entries {
            Some(it) => &*it,
            None => &[],
        }
    }
}

impl Attrs {
    pub const EMPTY: Attrs = Attrs { entries: None };

    pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
        match def {
            AttrDefId::ModuleId(module) => {
                let def_map = db.crate_def_map(module.krate);
                let mod_data = &def_map[module.local_id];
                match mod_data.declaration_source(db) {
                    Some(it) => {
                        Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner))
                    }
                    None => Attrs::from_attrs_owner(
                        db,
                        mod_data.definition_source(db).as_ref().map(|src| match src {
                            ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
                            ModuleSource::Module(module) => module as &dyn AttrsOwner,
                        }),
                    ),
                }
            }
            AttrDefId::FieldId(it) => {
                let src = it.parent.child_source(db);
                match &src.value[it.local_id] {
                    Either::Left(_tuple) => Attrs::default(),
                    Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
                }
            }
            AttrDefId::EnumVariantId(var_id) => {
                let src = var_id.parent.child_source(db);
                let src = src.as_ref().map(|it| &it[var_id.local_id]);
                Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
            }
            AttrDefId::AdtId(it) => match it {
                AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
                AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
                AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            },
            AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::MacroDefId(it) => {
                it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
            }
            AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
        }
    }

    pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs {
        let hygiene = Hygiene::new(db.upcast(), owner.file_id);
        Attrs::new(owner.value, &hygiene)
    }

    pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
        let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map(
            |docs_text| Attr {
                input: Some(AttrInput::Literal(SmolStr::new(docs_text))),
                path: ModPath::from(hir_expand::name!(doc)),
            },
        );
        let mut attrs = owner.attrs().peekable();
        let entries = if attrs.peek().is_none() {
            // Avoid heap allocation
            None
        } else {
            Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect())
        };
        Attrs { entries }
    }

    pub fn merge(&self, other: Attrs) -> Attrs {
        match (&self.entries, &other.entries) {
            (None, None) => Attrs { entries: None },
            (Some(entries), None) | (None, Some(entries)) => {
                Attrs { entries: Some(entries.clone()) }
            }
            (Some(a), Some(b)) => {
                Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
            }
        }
    }

    pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
        AttrQuery { attrs: self, key }
    }

    pub fn cfg(&self) -> impl Iterator<Item = CfgExpr> + '_ {
        // FIXME: handle cfg_attr :-)
        self.by_key("cfg").tt_values().map(CfgExpr::parse)
    }
    pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
        self.cfg().all(|cfg| cfg_options.check(&cfg) != Some(false))
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Attr {
    pub(crate) path: ModPath,
    pub(crate) input: Option<AttrInput>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttrInput {
    /// `#[attr = "string"]`
    Literal(SmolStr),
    /// `#[attr(subtree)]`
    TokenTree(Subtree),
}

impl Attr {
    fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
        let path = ModPath::from_src(ast.path()?, hygiene)?;
        let input = if let Some(lit) = ast.literal() {
            // FIXME: escape? raw string?
            let value = lit.syntax().first_token()?.text().trim_matches('"').into();
            Some(AttrInput::Literal(value))
        } else if let Some(tt) = ast.token_tree() {
            Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
        } else {
            None
        };
        Some(Attr { path, input })
    }
}

#[derive(Debug, Clone, Copy)]
pub struct AttrQuery<'a> {
    attrs: &'a Attrs,
    key: &'static str,
}

impl<'a> AttrQuery<'a> {
    pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
        self.attrs().filter_map(|attr| match attr.input.as_ref()? {
            AttrInput::TokenTree(it) => Some(it),
            _ => None,
        })
    }

    pub fn string_value(self) -> Option<&'a SmolStr> {
        self.attrs().find_map(|attr| match attr.input.as_ref()? {
            AttrInput::Literal(it) => Some(it),
            _ => None,
        })
    }

    pub fn exists(self) -> bool {
        self.attrs().next().is_some()
    }

    fn attrs(self) -> impl Iterator<Item = &'a Attr> {
        let key = self.key;
        self.attrs
            .iter()
            .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key))
    }
}

fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs
where
    N: ast::AttrsOwner,
{
    let src = InFile::new(src.file_id, src.to_node(db.upcast()));
    Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
}

fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs {
    let tree = db.item_tree(id.file_id);
    let mod_item = N::id_to_mod_item(id.value);
    tree.attrs(mod_item.into()).clone()
}
<|endoftext|>


<commit_before>use raw::Local;

extern "system" {

    #[link_name = "NeonSys_Mem_SameHandle"]
    pub fn same_handle(h1: Local, h2: Local) -> bool;

}
<commit_msg>expand neon_sys::mem mod documentation<commit_after>//! A helper function for comparing `v8::Local` handles.
use raw::Local;

extern "system" {

    /// Indicates if two `v8::Local` handles are the same.
    #[link_name = "NeonSys_Mem_SameHandle"]
    pub fn same_handle(h1: Local, h2: Local) -> bool;

}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use hir::{FromSource, ImplBlock};
use ra_db::SourceDatabase;
use ra_syntax::{algo::find_node_at_offset, ast, AstNode};

use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo};

pub(crate) fn goto_implementation(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    let parse = db.parse(position.file_id);
    let syntax = parse.tree().syntax().clone();

    let src = hir::ModuleSource::from_position(db, position);
    let module = hir::Module::from_definition(
        db,
        hir::InFile { file_id: position.file_id.into(), value: src },
    )?;

    if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(&syntax, position.offset) {
        return Some(RangeInfo::new(
            nominal_def.syntax().text_range(),
            impls_for_def(db, position, &nominal_def, module)?,
        ));
    } else if let Some(trait_def) = find_node_at_offset::<ast::TraitDef>(&syntax, position.offset) {
        return Some(RangeInfo::new(
            trait_def.syntax().text_range(),
            impls_for_trait(db, position, &trait_def, module)?,
        ));
    }

    None
}

fn impls_for_def(
    db: &RootDatabase,
    position: FilePosition,
    node: &ast::NominalDef,
    module: hir::Module,
) -> Option<Vec<NavigationTarget>> {
    let ty = match node {
        ast::NominalDef::StructDef(def) => {
            let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
            hir::Struct::from_source(db, src)?.ty(db)
        }
        ast::NominalDef::EnumDef(def) => {
            let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
            hir::Enum::from_source(db, src)?.ty(db)
        }
        ast::NominalDef::UnionDef(def) => {
            let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
            hir::Union::from_source(db, src)?.ty(db)
        }
    };

    let krate = module.krate();
    let impls = ImplBlock::all_in_crate(db, krate);

    Some(
        impls
            .into_iter()
            .filter(|impl_block| ty.is_equal_for_find_impls(&impl_block.target_ty(db)))
            .map(|imp| imp.to_nav(db))
            .collect(),
    )
}

fn impls_for_trait(
    db: &RootDatabase,
    position: FilePosition,
    node: &ast::TraitDef,
    module: hir::Module,
) -> Option<Vec<NavigationTarget>> {
    let src = hir::InFile { file_id: position.file_id.into(), value: node.clone() };
    let tr = hir::Trait::from_source(db, src)?;

    let krate = module.krate();
    let impls = ImplBlock::for_trait(db, krate, tr);

    Some(impls.into_iter().map(|imp| imp.to_nav(db)).collect())
}

#[cfg(test)]
mod tests {
    use crate::mock_analysis::analysis_and_position;

    fn check_goto(fixture: &str, expected: &[&str]) {
        let (analysis, pos) = analysis_and_position(fixture);

        let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
        assert_eq!(navs.len(), expected.len());
        navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start()));
        navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i]));
    }

    #[test]
    fn goto_implementation_works() {
        check_goto(
            "
            //- /lib.rs
            struct Foo<|>;
            impl Foo {}
            ",
            &["impl IMPL_BLOCK FileId(1) [12; 23)"],
        );
    }

    #[test]
    fn goto_implementation_works_multiple_blocks() {
        check_goto(
            "
            //- /lib.rs
            struct Foo<|>;
            impl Foo {}
            impl Foo {}
            ",
            &["impl IMPL_BLOCK FileId(1) [12; 23)", "impl IMPL_BLOCK FileId(1) [24; 35)"],
        );
    }

    #[test]
    fn goto_implementation_works_multiple_mods() {
        check_goto(
            "
            //- /lib.rs
            struct Foo<|>;
            mod a {
                impl super::Foo {}
            }
            mod b {
                impl super::Foo {}
            }
            ",
            &["impl IMPL_BLOCK FileId(1) [24; 42)", "impl IMPL_BLOCK FileId(1) [57; 75)"],
        );
    }

    #[test]
    fn goto_implementation_works_multiple_files() {
        check_goto(
            "
            //- /lib.rs
            struct Foo<|>;
            mod a;
            mod b;
            //- /a.rs
            impl crate::Foo {}
            //- /b.rs
            impl crate::Foo {}
            ",
            &["impl IMPL_BLOCK FileId(2) [0; 18)", "impl IMPL_BLOCK FileId(3) [0; 18)"],
        );
    }

    #[test]
    fn goto_implementation_for_trait() {
        check_goto(
            "
            //- /lib.rs
            trait T<|> {}
            struct Foo;
            impl T for Foo {}
            ",
            &["impl IMPL_BLOCK FileId(1) [23; 40)"],
        );
    }

    #[test]
    fn goto_implementation_for_trait_multiple_files() {
        check_goto(
            "
            //- /lib.rs
            trait T<|> {};
            struct Foo;
            mod a;
            mod b;
            //- /a.rs
            impl crate::T for crate::Foo {}
            //- /b.rs
            impl crate::T for crate::Foo {}
            ",
            &["impl IMPL_BLOCK FileId(2) [0; 31)", "impl IMPL_BLOCK FileId(3) [0; 31)"],
        );
    }

    #[test]
    fn goto_implementation_all_impls() {
        check_goto(
            "
            //- /lib.rs
            trait T {}
            struct Foo<|>;
            impl Foo {}
            impl T for Foo {}
            impl T for &Foo {}
            ",
            &[
                "impl IMPL_BLOCK FileId(1) [23; 34)",
                "impl IMPL_BLOCK FileId(1) [35; 52)",
                "impl IMPL_BLOCK FileId(1) [53; 71)",
            ],
        );
    }
}
<commit_msg>Add test<commit_after>//! FIXME: write short doc here

use hir::{FromSource, ImplBlock};
use ra_db::SourceDatabase;
use ra_syntax::{algo::find_node_at_offset, ast, AstNode};

use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo};

pub(crate) fn goto_implementation(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    let parse = db.parse(position.file_id);
    let syntax = parse.tree().syntax().clone();

    let src = hir::ModuleSource::from_position(db, position);
    let module = hir::Module::from_definition(
        db,
        hir::InFile { file_id: position.file_id.into(), value: src },
    )?;

    if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(&syntax, position.offset) {
        return Some(RangeInfo::new(
            nominal_def.syntax().text_range(),
            impls_for_def(db, position, &nominal_def, module)?,
        ));
    } else if let Some(trait_def) = find_node_at_offset::<ast::TraitDef>(&syntax, position.offset) {
        return Some(RangeInfo::new(
            trait_def.syntax().text_range(),
            impls_for_trait(db, position, &trait_def, module)?,
        ));
    }

    None
}

fn impls_for_def(
    db: &RootDatabase,
    position: FilePosition,
    node: &ast::NominalDef,
    module: hir::Module,
) -> Option<Vec<NavigationTarget>> {
    let ty = match node {
        ast::NominalDef::StructDef(def) => {
            let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
            hir::Struct::from_source(db, src)?.ty(db)
        }
        ast::NominalDef::EnumDef(def) => {
            let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
            hir::Enum::from_source(db, src)?.ty(db)
        }
        ast::NominalDef::UnionDef(def) => {
            let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
            hir::Union::from_source(db, src)?.ty(db)
        }
    };

    let krate = module.krate();
    let impls = ImplBlock::all_in_crate(db, krate);

    Some(
        impls
            .into_iter()
            .filter(|impl_block| ty.is_equal_for_find_impls(&impl_block.target_ty(db)))
            .map(|imp| imp.to_nav(db))
            .collect(),
    )
}

fn impls_for_trait(
    db: &RootDatabase,
    position: FilePosition,
    node: &ast::TraitDef,
    module: hir::Module,
) -> Option<Vec<NavigationTarget>> {
    let src = hir::InFile { file_id: position.file_id.into(), value: node.clone() };
    let tr = hir::Trait::from_source(db, src)?;

    let krate = module.krate();
    let impls = ImplBlock::for_trait(db, krate, tr);

    Some(impls.into_iter().map(|imp| imp.to_nav(db)).collect())
}

#[cfg(test)]
mod tests {
    use crate::mock_analysis::analysis_and_position;

    fn check_goto(fixture: &str, expected: &[&str]) {
        let (analysis, pos) = analysis_and_position(fixture);

        let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
        assert_eq!(navs.len(), expected.len());
        navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start()));
        navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i]));
    }

    #[test]
    fn goto_implementation_works() {
        check_goto(
            "
            //- /lib.rs
            struct Foo<|>;
            impl Foo {}
            ",
            &["impl IMPL_BLOCK FileId(1) [12; 23)"],
        );
    }

    #[test]
    fn goto_implementation_works_multiple_blocks() {
        check_goto(
            "
            //- /lib.rs
            struct Foo<|>;
            impl Foo {}
            impl Foo {}
            ",
            &["impl IMPL_BLOCK FileId(1) [12; 23)", "impl IMPL_BLOCK FileId(1) [24; 35)"],
        );
    }

    #[test]
    fn goto_implementation_works_multiple_mods() {
        check_goto(
            "
            //- /lib.rs
            struct Foo<|>;
            mod a {
                impl super::Foo {}
            }
            mod b {
                impl super::Foo {}
            }
            ",
            &["impl IMPL_BLOCK FileId(1) [24; 42)", "impl IMPL_BLOCK FileId(1) [57; 75)"],
        );
    }

    #[test]
    fn goto_implementation_works_multiple_files() {
        check_goto(
            "
            //- /lib.rs
            struct Foo<|>;
            mod a;
            mod b;
            //- /a.rs
            impl crate::Foo {}
            //- /b.rs
            impl crate::Foo {}
            ",
            &["impl IMPL_BLOCK FileId(2) [0; 18)", "impl IMPL_BLOCK FileId(3) [0; 18)"],
        );
    }

    #[test]
    fn goto_implementation_for_trait() {
        check_goto(
            "
            //- /lib.rs
            trait T<|> {}
            struct Foo;
            impl T for Foo {}
            ",
            &["impl IMPL_BLOCK FileId(1) [23; 40)"],
        );
    }

    #[test]
    fn goto_implementation_for_trait_multiple_files() {
        check_goto(
            "
            //- /lib.rs
            trait T<|> {};
            struct Foo;
            mod a;
            mod b;
            //- /a.rs
            impl crate::T for crate::Foo {}
            //- /b.rs
            impl crate::T for crate::Foo {}
            ",
            &["impl IMPL_BLOCK FileId(2) [0; 31)", "impl IMPL_BLOCK FileId(3) [0; 31)"],
        );
    }

    #[test]
    fn goto_implementation_all_impls() {
        check_goto(
            "
            //- /lib.rs
            trait T {}
            struct Foo<|>;
            impl Foo {}
            impl T for Foo {}
            impl T for &Foo {}
            ",
            &[
                "impl IMPL_BLOCK FileId(1) [23; 34)",
                "impl IMPL_BLOCK FileId(1) [35; 52)",
                "impl IMPL_BLOCK FileId(1) [53; 71)",
            ],
        );
    }

    #[test]
    fn goto_implementation_to_builtin_derive() {
        check_goto(
            "
            //- /lib.rs
            #[derive(Copy)]
            struct Foo<|>;
            ",
            &["impl IMPL_BLOCK FileId(1) [0; 15)"],
        );
    }
}
<|endoftext|>