<commit_before>#[doc (hidden)]
#[macro_export]
macro_rules! time_steward_define_simple_timeline {
  () => {
pub mod simple_timeline {
use std::collections::BTreeSet;
use std::mem;
use std::cell::RefCell;
use std::marker::PhantomData;

use super::super::super::api::*;
use super::*;
use implementation_support::common::{split_off_greater_set};

#[derive (Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
pub struct GetVarying;
impl StewardData for GetVarying {}

#[serde(bound = "")]
#[derive (Serialize, Deserialize, Derivative)]
#[derivative (Clone (bound=""), Debug (bound=""))]
pub struct SimpleTimeline <VaryingData: StewardData, Steward: TimeSteward> {
  // Hacky workaround for https://github.com/rust-lang/rust/issues/41617 (see https://github.com/serde-rs/serde/issues/943)
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  changes: Vec<(<Steward as TimeSteward>::EventHandle, Option <VaryingData>)>,
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  other_dependent_events: RefCell<BTreeSet<<Steward as TimeSteward>::EventHandle>>,
}

impl <VaryingData: StewardData, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  pub fn new ()->Self {
    SimpleTimeline {
      changes: Vec::new(),
      other_dependent_events: RefCell::new (BTreeSet::new()),
    }
  }

  fn invalidate_after <Accessor: InvalidationAccessor<Steward = Steward>> (&self, time: &ExtendedTime <<Steward as TimeSteward>::Basics>, accessor: & Accessor) {
    let mut dependencies = self.other_dependent_events.borrow_mut();
    let removed = split_off_greater_set (&mut *dependencies, time);
    for event in removed {
      accessor.invalidate(&event);
    }
    for change in self.changes.iter().rev() {
      let event = &change.0;
      if event.extended_time() <= time {
        break
      }
      accessor.invalidate(&event);
    }
  }

  fn remove_from (&mut self, time: &ExtendedTime <Steward::Basics>) {
    while let Some (change) = self.changes.pop() {
      if change.0.extended_time() < time {
        self.changes.push (change);
        break
      }
    }
  }

  fn search_changes (&self, time: &ExtendedTime <Steward::Basics>) -> Result <usize, usize> {
    // search at the end first, because we are usually in the present.
    match self.changes.last() {
      None => return Err(0),
      Some (&(ref event, ref data)) => {
        match event.extended_time().cmp(time) {
          Ordering::Greater => (),
          Ordering::Equal => return Ok(self.changes.len()-1),
          Ordering::Less => return Err(self.changes.len()),
        }
      },
    }
    self.changes[..self.changes.len()-1].binary_search_by_key (&time, | change | change.0.extended_time())
  }
}

impl <VaryingData: StewardData, Steward: TimeSteward> DataTimeline for SimpleTimeline <VaryingData, Steward> {
  type Basics = Steward::Basics;

  fn clone_for_snapshot (&self, time: &ExtendedTime <Self::Basics>)->Self {
    let slice = match self.search_changes(&time) {
      Ok(index) => &self.changes [index.saturating_sub (1).. index+1],
      Err (index) => &self.changes [index.saturating_sub (1)..index],
    };
    SimpleTimeline {
      changes: slice.to_vec(),
      other_dependent_events: RefCell::new (BTreeSet::new()),
    }
  }

  fn forget_before (&mut self, time: &ExtendedTime <Self::Basics>) {
    let mut dependencies = self.other_dependent_events.borrow_mut();
    let retained = dependencies.split_off (time);
    mem::replace (&mut*dependencies, retained);

    if self.changes.len() > 0 && self.changes [self.changes.len()/2].0.extended_time() < time {
      let keep_from_index = match self.search_changes(&time) {
        Ok (index) => index,
        Err(index) => index - 1,
      };
      self.changes = self.changes.split_off (keep_from_index);
    }
  }
}
impl <VaryingData: StewardData, Steward: TimeSteward> DataTimelineQueriableWith<GetVarying> for SimpleTimeline <VaryingData, Steward> {
  type QueryResult = Option <(ExtendedTime <Self::Basics>, VaryingData)>;

  fn query (&self, _: &GetVarying, time: &ExtendedTime <Self::Basics>, offset: QueryOffset)->Self::QueryResult {
    let previous_change_index = match self.search_changes(&time) {
      Ok(index) => match offset {QueryOffset::After => index, QueryOffset::Before => index.wrapping_sub (1)},
      Err (index) => index.wrapping_sub (1),
    };
    self.changes.get (previous_change_index).and_then (| change | change.1.as_ref().map (| data | (change.0.extended_time().clone(), data.clone())))
  }
}

struct InvalidatorStruct <'a, Steward: TimeSteward, VaryingData: StewardData>{
  handle: &'a DataTimelineCell <SimpleTimeline <VaryingData, Steward>>,
}
impl<'a, Steward: TimeSteward, VaryingData: StewardData> Invalidator for InvalidatorStruct<'a, Steward, VaryingData> {
  type Steward = Steward;
  fn execute<Accessor: InvalidationAccessor <Steward = Self::Steward>> (self, accessor: &Accessor) {
    accessor.peek(self.handle, | timeline | timeline.invalidate_after (accessor.extended_now(), accessor));
  }
}

pub fn tracking_query <VaryingData: StewardData, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, offset: QueryOffset)->Option <(ExtendedTime <Steward::Basics>, VaryingData)> {
  accessor.modify (handle, move |timeline| {
    let mut dependencies = timeline.other_dependent_events.borrow_mut();
    dependencies.insert (accessor.handle().clone());
  });
  accessor.query (handle, &GetVarying, offset)
}
pub fn modify_simple_timeline <VaryingData: StewardData, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, modification: Option <VaryingData>) {
  match accessor.query (handle, &GetVarying, QueryOffset::After) {
    Some((time, data)) =>
      if let Some (new_data) = modification.as_ref() {
        if &time == accessor.extended_now() && &data == new_data {
          return
        }
      },
    None =>
      if modification.is_none() {return}
  };
  accessor.invalidate (InvalidatorStruct{handle: handle});
  accessor.modify (handle, move |timeline| {
    timeline.remove_from (accessor.extended_now());
    timeline.changes.push ((accessor.handle().clone(), modification));
  });
}
pub fn unmodify_simple_timeline <VaryingData: StewardData, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>) {
  if let Some((time, _)) = accessor.query (handle, &GetVarying, QueryOffset::After) { if &time == accessor.extended_now() {
    accessor.invalidate (InvalidatorStruct{handle: handle});
    accessor.modify (handle, move |timeline| {
      timeline.remove_from (accessor.extended_now());
    });
  }}
}

} //mod

  };
}

<commit_msg>add some debug checks<commit_after>#[doc (hidden)]
#[macro_export]
macro_rules! time_steward_define_simple_timeline {
  () => {
pub mod simple_timeline {
use std::collections::BTreeSet;
use std::mem;
use std::cell::RefCell;
use std::marker::PhantomData;

use super::super::super::api::*;
use super::*;
use implementation_support::common::{split_off_greater_set};

#[derive (Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
pub struct GetVarying;
impl StewardData for GetVarying {}

#[serde(bound = "")]
#[derive (Serialize, Deserialize, Derivative)]
#[derivative (Clone (bound=""), Debug (bound=""))]
pub struct SimpleTimeline <VaryingData: StewardData, Steward: TimeSteward> {
  // Hacky workaround for https://github.com/rust-lang/rust/issues/41617 (see https://github.com/serde-rs/serde/issues/943)
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  changes: Vec<(<Steward as TimeSteward>::EventHandle, Option <VaryingData>)>,
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  other_dependent_events: RefCell<BTreeSet<<Steward as TimeSteward>::EventHandle>>,
}

impl <VaryingData: StewardData, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  pub fn new ()->Self {
    SimpleTimeline {
      changes: Vec::new(),
      other_dependent_events: RefCell::new (BTreeSet::new()),
    }
  }

  fn invalidate_after <Accessor: InvalidationAccessor<Steward = Steward>> (&self, time: &ExtendedTime <<Steward as TimeSteward>::Basics>, accessor: & Accessor) {
    let mut dependencies = self.other_dependent_events.borrow_mut();
    let removed = split_off_greater_set (&mut *dependencies, time);
    for event in removed {
      accessor.invalidate(&event);
    }
    for change in self.changes.iter().rev() {
      let event = &change.0;
      if event.extended_time() <= time {
        break
      }
      accessor.invalidate(&event);
    }
  }

  fn remove_from (&mut self, time: &ExtendedTime <Steward::Basics>) {
    while let Some (change) = self.changes.pop() {
      if change.0.extended_time() < time {
        self.changes.push (change);
        break
      }
    }
  }

  fn search_changes (&self, time: &ExtendedTime <Steward::Basics>) -> Result <usize, usize> {
    // search at the end first, because we are usually in the present.
    match self.changes.last() {
      None => return Err(0),
      Some (&(ref event, ref data)) => {
        match event.extended_time().cmp(time) {
          Ordering::Greater => (),
          Ordering::Equal => return Ok(self.changes.len()-1),
          Ordering::Less => return Err(self.changes.len()),
        }
      },
    }
    self.changes[..self.changes.len()-1].binary_search_by_key (&time, | change | change.0.extended_time())
  }
}

impl <VaryingData: StewardData, Steward: TimeSteward> DataTimeline for SimpleTimeline <VaryingData, Steward> {
  type Basics = Steward::Basics;

  fn clone_for_snapshot (&self, time: &ExtendedTime <Self::Basics>)->Self {
    let slice = match self.search_changes(&time) {
      Ok(index) => &self.changes [index.saturating_sub (1).. index+1],
      Err (index) => &self.changes [index.saturating_sub (1)..index],
    };
    SimpleTimeline {
      changes: slice.to_vec(),
      other_dependent_events: RefCell::new (BTreeSet::new()),
    }
  }

  fn forget_before (&mut self, time: &ExtendedTime <Self::Basics>) {
    let mut dependencies = self.other_dependent_events.borrow_mut();
    let retained = dependencies.split_off (time);
    mem::replace (&mut*dependencies, retained);

    if self.changes.len() > 0 && self.changes [self.changes.len()/2].0.extended_time() < time {
      let keep_from_index = match self.search_changes(&time) {
        Ok (index) => index,
        Err(index) => index - 1,
      };
      self.changes = self.changes.split_off (keep_from_index);
    }
  }
}
impl <VaryingData: StewardData, Steward: TimeSteward> DataTimelineQueriableWith<GetVarying> for SimpleTimeline <VaryingData, Steward> {
  type QueryResult = Option <(ExtendedTime <Self::Basics>, VaryingData)>;

  fn query (&self, _: &GetVarying, time: &ExtendedTime <Self::Basics>, offset: QueryOffset)->Self::QueryResult {
    let previous_change_index = match self.search_changes(&time) {
      Ok(index) => match offset {QueryOffset::After => index, QueryOffset::Before => index.wrapping_sub (1)},
      Err (index) => index.wrapping_sub (1),
    };
    self.changes.get (previous_change_index).and_then (| change | change.1.as_ref().map (| data | (change.0.extended_time().clone(), data.clone())))
  }
}

struct InvalidatorStruct <'a, Steward: TimeSteward, VaryingData: StewardData>{
  handle: &'a DataTimelineCell <SimpleTimeline <VaryingData, Steward>>,
}
impl<'a, Steward: TimeSteward, VaryingData: StewardData> Invalidator for InvalidatorStruct<'a, Steward, VaryingData> {
  type Steward = Steward;
  fn execute<Accessor: InvalidationAccessor <Steward = Self::Steward>> (self, accessor: &Accessor) {
    accessor.peek(self.handle, | timeline | timeline.invalidate_after (accessor.extended_now(), accessor));
  }
}

pub fn tracking_query <VaryingData: StewardData, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, offset: QueryOffset)->Option <(ExtendedTime <Steward::Basics>, VaryingData)> {
  accessor.modify (handle, move |timeline| {
    let mut dependencies = timeline.other_dependent_events.borrow_mut();
    dependencies.insert (accessor.handle().clone());
  });
  accessor.query (handle, &GetVarying, offset)
}
pub fn modify_simple_timeline <VaryingData: StewardData, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, modification: Option <VaryingData>) {
  #[cfg (debug_assertions)]
  let confirm1 = accessor.query (handle, &GetVarying, QueryOffset::Before);
  match accessor.query (handle, &GetVarying, QueryOffset::After) {
    Some((time, data)) =>
      if let Some (new_data) = modification.as_ref() {
        if &time == accessor.extended_now() && &data == new_data {
          return
        }
      },
    None =>
      if modification.is_none() {return}
  };
  accessor.invalidate (InvalidatorStruct{handle: handle});
  #[cfg (debug_assertions)]
  let confirm2 = modification.clone().map(|data|(accessor.extended_now().clone(), data));
  accessor.modify (handle, move |timeline| {
    timeline.remove_from (accessor.extended_now());
    timeline.changes.push ((accessor.handle().clone(), modification));
  });
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm1);
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::After) == confirm2);
}
pub fn unmodify_simple_timeline <VaryingData: StewardData, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>) {
  #[cfg (debug_assertions)]
  let confirm = accessor.query (handle, &GetVarying, QueryOffset::Before);
  if let Some((time, _)) = accessor.query (handle, &GetVarying, QueryOffset::After) { if &time == accessor.extended_now() {
    accessor.invalidate (InvalidatorStruct{handle: handle});
    accessor.modify (handle, move |timeline| {
      timeline.remove_from (accessor.extended_now());
    });
  }}
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm);
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::After) == confirm);
}

} //mod

  };
}

<|endoftext|>


<commit_before>use crate::{
    core::*,
    fa::{Approximator, VectorLFA, Parameterised, Projector},
    policies::{
        sample_probs_with_rng,
        DifferentiablePolicy,
        ParameterisedPolicy,
        FinitePolicy,
        Policy
    },
    utils::argmax_choose,
};
use rand::{rngs::ThreadRng, thread_rng, Rng};
use std::{f64, ops::AddAssign};

pub struct Gibbs<F> {
    pub fa: F,

    rng: ThreadRng,
}

fn probabilities_from_values(values: &[f64]) -> Vector<f64> {
    let mut z = 0.0;
    let ws: Vec<f64> = values
        .iter()
        .map(|v| {
            let v = v.exp();
            z += v;

            v
        })
        .collect();

    ws.iter().map(|w| (w / z).min(1e50)).collect()
}

impl<F> Gibbs<F> {
    pub fn new(fa: F) -> Self {
        Gibbs {
            fa,

            rng: thread_rng(),
        }
    }
}

impl<F> Algorithm for Gibbs<F> {}

impl<S, M: Projector<S>> Policy<S> for Gibbs<VectorLFA<M>> {
    type Action = usize;

    fn sample(&mut self, s: &S) -> usize {
        let ps = self.probabilities(s);

        sample_probs_with_rng(&mut self.rng, ps.as_slice().unwrap())
    }

    fn mpa(&mut self, s: &S) -> usize {
        let ps = self.probabilities(s);

        argmax_choose(&mut self.rng, ps.as_slice().unwrap()).1
    }

    fn probability(&mut self, input: &S, a: usize) -> f64 { self.probabilities(input)[a] }
}

impl<S, M: Projector<S>> FinitePolicy<S> for Gibbs<VectorLFA<M>> {
    fn n_actions(&self) -> usize {
        self.fa.n_outputs()
    }

    fn probabilities(&mut self, input: &S) -> Vector<f64> {
        let values = self.fa.evaluate(input).unwrap();

        probabilities_from_values(values.as_slice().unwrap())
    }
}

impl<S, M: Projector<S>> DifferentiablePolicy<S> for Gibbs<VectorLFA<M>> {
    fn grad_log(&self, input: &S, a: usize) -> Matrix<f64> {
        let phi = self.fa.projector.project(input);

        let values = self.fa.evaluate_primal(&phi).unwrap();
        let n_actions = values.len();
        let probabilities = probabilities_from_values(values.as_slice().unwrap())
            .into_shape((1, n_actions))
            .unwrap();

        let dim = self.fa.projector.dim();
        let phi = phi.expanded(self.fa.projector.dim());

        let mut grad_log = phi
            .clone()
            .into_shape((dim, 1))
            .unwrap()
            .dot(&-probabilities);
        grad_log.column_mut(a).add_assign(&phi);

        grad_log
    }
}

impl<F: Parameterised> Parameterised for Gibbs<F> {
    fn weights(&self) -> Matrix<f64> { self.fa.weights() }
}

impl<S, M: Projector<S>> ParameterisedPolicy<S> for Gibbs<VectorLFA<M>> {
    fn update(&mut self, input: &S, a: usize, error: f64) {
        let grad_log = self.grad_log(input, a);

        self.fa
            .approximator
            .weights
            .scaled_add(error, &grad_log);
    }

    fn update_raw(&mut self, errors: Matrix<f64>) {
        self.fa.approximator.weights.add_assign(&errors)
    }
}

#[cfg(test)]
mod tests {
    use crate::fa::{LFA, Parameterised, basis::fixed::Polynomial};
    use crate::policies::{Policy, ParameterisedPolicy};
    use super::Gibbs;

    #[test]
    fn test_sample() {
        let fa = LFA::vector_output(Polynomial::new(1, vec![(0.0, 1.0)]), 3);
        let mut p = Gibbs::new(fa);

        for _ in 0..10 {
            p.update(&vec![0.0], 0, -100.0);
            p.update(&vec![0.0], 1, 100.0);
            p.update(&vec![0.0], 2, -100.0);
        }

        assert_eq!(p.sample(&vec![0.0]), 1);
    }
}
<commit_msg>test(policies): fix test for Gibbs policy<commit_after>use crate::{
    core::*,
    fa::{Approximator, VectorLFA, Parameterised, Projector},
    policies::{
        sample_probs_with_rng,
        DifferentiablePolicy,
        ParameterisedPolicy,
        FinitePolicy,
        Policy
    },
    utils::argmax_choose,
};
use rand::{rngs::ThreadRng, thread_rng, Rng};
use std::{f64, ops::AddAssign};

pub struct Gibbs<F> {
    pub fa: F,

    rng: ThreadRng,
}

fn probabilities_from_values(values: &[f64]) -> Vector<f64> {
    let mut z = 0.0;
    let ws: Vec<f64> = values
        .iter()
        .map(|v| {
            let v = v.exp();
            z += v;

            v
        })
        .collect();

    ws.iter().map(|w| (w / z).min(1e50)).collect()
}

impl<F> Gibbs<F> {
    pub fn new(fa: F) -> Self {
        Gibbs {
            fa,

            rng: thread_rng(),
        }
    }
}

impl<F> Algorithm for Gibbs<F> {}

impl<S, M: Projector<S>> Policy<S> for Gibbs<VectorLFA<M>> {
    type Action = usize;

    fn sample(&mut self, s: &S) -> usize {
        let ps = self.probabilities(s);

        sample_probs_with_rng(&mut self.rng, ps.as_slice().unwrap())
    }

    fn mpa(&mut self, s: &S) -> usize {
        let ps = self.probabilities(s);

        argmax_choose(&mut self.rng, ps.as_slice().unwrap()).1
    }

    fn probability(&mut self, input: &S, a: usize) -> f64 { self.probabilities(input)[a] }
}

impl<S, M: Projector<S>> FinitePolicy<S> for Gibbs<VectorLFA<M>> {
    fn n_actions(&self) -> usize {
        self.fa.n_outputs()
    }

    fn probabilities(&mut self, input: &S) -> Vector<f64> {
        let values = self.fa.evaluate(input).unwrap();

        probabilities_from_values(values.as_slice().unwrap())
    }
}

impl<S, M: Projector<S>> DifferentiablePolicy<S> for Gibbs<VectorLFA<M>> {
    fn grad_log(&self, input: &S, a: usize) -> Matrix<f64> {
        let phi = self.fa.projector.project(input);

        let values = self.fa.evaluate_primal(&phi).unwrap();
        let n_actions = values.len();
        let probabilities = probabilities_from_values(values.as_slice().unwrap())
            .into_shape((1, n_actions))
            .unwrap();

        let dim = self.fa.projector.dim();
        let phi = phi.expanded(self.fa.projector.dim());

        let mut grad_log = phi
            .clone()
            .into_shape((dim, 1))
            .unwrap()
            .dot(&-probabilities);
        grad_log.column_mut(a).add_assign(&phi);

        grad_log
    }
}

impl<F: Parameterised> Parameterised for Gibbs<F> {
    fn weights(&self) -> Matrix<f64> { self.fa.weights() }
}

impl<S, M: Projector<S>> ParameterisedPolicy<S> for Gibbs<VectorLFA<M>> {
    fn update(&mut self, input: &S, a: usize, error: f64) {
        let grad_log = self.grad_log(input, a);

        self.fa
            .approximator
            .weights
            .scaled_add(error, &grad_log);
    }

    fn update_raw(&mut self, errors: Matrix<f64>) {
        self.fa.approximator.weights.add_assign(&errors)
    }
}

#[cfg(test)]
mod tests {
    use crate::fa::{LFA, Parameterised, basis::fixed::Polynomial};
    use crate::policies::{Policy, ParameterisedPolicy, FinitePolicy};
    use super::Gibbs;

    #[test]
    fn test_probabilities() {
        let fa = LFA::vector_output(Polynomial::new(0, vec![(0.0, 1.0)]), 3);
        let mut p = Gibbs::new(fa);

        p.update(&vec![0.0], 0, -1.0);
        p.update(&vec![0.0], 1, 1.0);
        p.update(&vec![0.0], 2, -1.0);

        let ps = p.probabilities(&vec![0.0]);

        assert!(ps[0] < ps[1]);
        assert!(ps[2] < ps[1]);
    }
}
<|endoftext|>


<commit_before>use log_parser::*;

#[derive(Clone, Debug, PartialEq)]
pub struct RequestResponsePair {
    pub request: log_events::Request,
    pub response: log_events::Response,
}

pub struct RequestResponsePairIterator<'a> {
    events: &'a mut Iterator<Item = log_events::LogEvent>,
    requests: Vec<log_events::Request>,
    responses: Vec<log_events::Response>,
}

impl<'a> RequestResponsePairIterator<'a> {
    pub fn new(events: &'a mut Iterator<Item = log_events::LogEvent>) -> Self {
        RequestResponsePairIterator {
            events: events,
            requests: vec![],
            responses: vec![],
        }
    }
}

impl<'a> Iterator for RequestResponsePairIterator<'a> {
    type Item = RequestResponsePair;

    fn next(&mut self) -> Option<RequestResponsePair> {
        let mut pair = None;

        while pair.is_none() {
            let event = self.events.next();

            match event {
                Some(log_events::LogEvent::Request(request)) => self.requests.push(request),
                Some(log_events::LogEvent::Response(response)) => self.responses.push(response),
                None => return None,
            }

            pair = extract_first_matching_request_response_pair(
                &mut self.requests,
                &mut self.responses,
            );
        }
        pair
    }
}

pub fn extract_first_matching_request_response_pair(
    requests: &mut Vec<log_events::Request>,
    responses: &mut Vec<log_events::Response>,
) -> Option<RequestResponsePair> {
    for request_index in 0..requests.len() {
        {
            let request = requests.get(request_index);

            if request.is_none() {
                continue;
            }
        }

        let matching_response_index: Option<usize> = responses.iter().position(|response| {
            requests[request_index].id == response.id
        });

        if matching_response_index.is_some() {
            let request = requests.remove(request_index);
            let response = responses.remove(matching_response_index.unwrap());

            let pair = RequestResponsePair {
                request: request,
                response: response,
            };

            return Some(pair);
        }
    }
    None
}

#[cfg(test)]
mod tests {
    use chrono::*;
    use super::*;
    use log_parser;
    use analyzer::Timing;
    use analyzer::aggregated_error_rates::HttpErrorState;

    #[test]
    fn test_extract_matching_request_response_pairs_iterator() {
        let events =
            vec![
                log_parser::log_events::LogEvent::Request(log_parser::log_events::Request {
                    id: 1,
                    time: DateTime::parse_from_str(
                        "08/Apr/2016:09:57:47 +0200",
                        "%d/%b/%Y:%H:%M:%S %z",
                    ).unwrap(),
                    original_log_line: "whatever".to_string(),
                }),
                log_parser::log_events::LogEvent::Response(log_parser::log_events::Response {
                    id: 1,
                    response_time: Duration::milliseconds(7),
                    original_log_line: "whatever".to_string(),
                    http_error: None,
                }),
            ];

        let mut events_iter = events.into_iter();
        let mut iterator = RequestResponsePairIterator::new(&mut events_iter);

        let result = iterator.next().unwrap();
        assert_eq!(result.request.id, 1);
    }

    #[test]
    fn test_timing_trait() {
        let timing: &Timing = &RequestResponsePair {
            request: log_parser::log_events::Request {
                id: 1,
                time: DateTime::parse_from_str(
                    "08/Apr/2016:09:57:47 +0200",
                    "%d/%b/%Y:%H:%M:%S %z",
                ).unwrap(),
                original_log_line: "whatever".to_string(),
            },
            response: log_parser::log_events::Response {
                id: 1,
                response_time: Duration::milliseconds(7),
                original_log_line: "whatever".to_string(),
                http_error: None,
            },
        } as &Timing;

        let result: i64 = timing.num_milliseconds();
        assert_eq!(result, 7);

        let boxed_timing = Box::new(timing);

        let result: i64 = boxed_timing.num_milliseconds();
        assert_eq!(result, 7);
    }

    #[test]
    fn test_http_error_state_trait() {
        let state: &HttpErrorState = &RequestResponsePair {
            request: log_parser::log_events::Request {
                id: 1,
                time: DateTime::parse_from_str(
                    "08/Apr/2016:09:57:47 +0200",
                    "%d/%b/%Y:%H:%M:%S %z",
                ).unwrap(),
                original_log_line: "whatever".to_string(),
            },
            response: log_parser::log_events::Response {
                id: 1,
                response_time: Duration::milliseconds(7),
                original_log_line: "whatever".to_string(),
                http_error: None,
            },
        } as &HttpErrorState;

        let result = state.error();
        assert_eq!(result, None);

        let boxed_state = Box::new(state);

        let result = boxed_state.error();
        assert_eq!(result, None);
    }
}
<commit_msg>Helper function can stay private<commit_after>use log_parser::*;

#[derive(Clone, Debug, PartialEq)]
pub struct RequestResponsePair {
    pub request: log_events::Request,
    pub response: log_events::Response,
}

pub struct RequestResponsePairIterator<'a> {
    events: &'a mut Iterator<Item = log_events::LogEvent>,
    requests: Vec<log_events::Request>,
    responses: Vec<log_events::Response>,
}

impl<'a> RequestResponsePairIterator<'a> {
    pub fn new(events: &'a mut Iterator<Item = log_events::LogEvent>) -> Self {
        RequestResponsePairIterator {
            events: events,
            requests: vec![],
            responses: vec![],
        }
    }
}

impl<'a> Iterator for RequestResponsePairIterator<'a> {
    type Item = RequestResponsePair;

    fn next(&mut self) -> Option<RequestResponsePair> {
        let mut pair = None;

        while pair.is_none() {
            let event = self.events.next();

            match event {
                Some(log_events::LogEvent::Request(request)) => self.requests.push(request),
                Some(log_events::LogEvent::Response(response)) => self.responses.push(response),
                None => return None,
            }

            pair = extract_first_matching_request_response_pair(
                &mut self.requests,
                &mut self.responses,
            );
        }
        pair
    }
}

fn extract_first_matching_request_response_pair(
    requests: &mut Vec<log_events::Request>,
    responses: &mut Vec<log_events::Response>,
) -> Option<RequestResponsePair> {
    for request_index in 0..requests.len() {
        {
            let request = requests.get(request_index);

            if request.is_none() {
                continue;
            }
        }

        let matching_response_index: Option<usize> = responses.iter().position(|response| {
            requests[request_index].id == response.id
        });

        if matching_response_index.is_some() {
            let request = requests.remove(request_index);
            let response = responses.remove(matching_response_index.unwrap());

            let pair = RequestResponsePair {
                request: request,
                response: response,
            };

            return Some(pair);
        }
    }
    None
}

#[cfg(test)]
mod tests {
    use chrono::*;
    use super::*;
    use log_parser;
    use analyzer::Timing;
    use analyzer::aggregated_error_rates::HttpErrorState;

    #[test]
    fn test_extract_matching_request_response_pairs_iterator() {
        let events =
            vec![
                log_parser::log_events::LogEvent::Request(log_parser::log_events::Request {
                    id: 1,
                    time: DateTime::parse_from_str(
                        "08/Apr/2016:09:57:47 +0200",
                        "%d/%b/%Y:%H:%M:%S %z",
                    ).unwrap(),
                    original_log_line: "whatever".to_string(),
                }),
                log_parser::log_events::LogEvent::Response(log_parser::log_events::Response {
                    id: 1,
                    response_time: Duration::milliseconds(7),
                    original_log_line: "whatever".to_string(),
                    http_error: None,
                }),
            ];

        let mut events_iter = events.into_iter();
        let mut iterator = RequestResponsePairIterator::new(&mut events_iter);

        let result = iterator.next().unwrap();
        assert_eq!(result.request.id, 1);
    }

    #[test]
    fn test_timing_trait() {
        let timing: &Timing = &RequestResponsePair {
            request: log_parser::log_events::Request {
                id: 1,
                time: DateTime::parse_from_str(
                    "08/Apr/2016:09:57:47 +0200",
                    "%d/%b/%Y:%H:%M:%S %z",
                ).unwrap(),
                original_log_line: "whatever".to_string(),
            },
            response: log_parser::log_events::Response {
                id: 1,
                response_time: Duration::milliseconds(7),
                original_log_line: "whatever".to_string(),
                http_error: None,
            },
        } as &Timing;

        let result: i64 = timing.num_milliseconds();
        assert_eq!(result, 7);

        let boxed_timing = Box::new(timing);

        let result: i64 = boxed_timing.num_milliseconds();
        assert_eq!(result, 7);
    }

    #[test]
    fn test_http_error_state_trait() {
        let state: &HttpErrorState = &RequestResponsePair {
            request: log_parser::log_events::Request {
                id: 1,
                time: DateTime::parse_from_str(
                    "08/Apr/2016:09:57:47 +0200",
                    "%d/%b/%Y:%H:%M:%S %z",
                ).unwrap(),
                original_log_line: "whatever".to_string(),
            },
            response: log_parser::log_events::Response {
                id: 1,
                response_time: Duration::milliseconds(7),
                original_log_line: "whatever".to_string(),
                http_error: None,
            },
        } as &HttpErrorState;

        let result = state.error();
        assert_eq!(result, None);

        let boxed_state = Box::new(state);

        let result = boxed_state.error();
        assert_eq!(result, None);
    }
}
<|endoftext|>


<commit_before>use crate::prelude::*;
use crate::ComItf;

#[derive(Debug, Clone, Copy, Hash, PartialOrd, PartialEq)]
#[repr(C)]
pub enum TypeSystemName
{
    Automation = 0,
    Raw = 1,
}

impl TypeSystemName
{
    pub fn get_ptr<I: ?Sized>(self, itf: &ComItf<I>) -> crate::raw::RawComPtr
    {
        let opt = match self {
            TypeSystemName::Automation => AutomationTypeSystem::get_ptr(itf).map(|p| p.ptr),
            TypeSystemName::Raw => RawTypeSystem::get_ptr(itf).map(|p| p.ptr),
        };

        match opt {
            Some(ptr) => ptr.as_ptr(),
            None => std::ptr::null_mut(),
        }
    }
}

/// Common trait for type systems.
pub trait TypeSystem: Clone + Copy
{
    const AUTOMATION: TypeSystemName = TypeSystemName::Automation;
    const RAW: TypeSystemName = TypeSystemName::Raw;

    fn key() -> TypeSystemName;

    /// Gets the type system pointer from a ComItf.
    fn get_ptr<I: ?Sized>(itf: &ComItf<I>) -> Option<crate::raw::InterfacePtr<Self, I>>;

    /// Constructs a ComItf from a pointer.
    fn wrap_ptr<I: ?Sized>(ptr: crate::raw::InterfacePtr<Self, I>) -> ComItf<I>;
}

/// Automation type system.
#[derive(Clone, Copy)]
pub struct AutomationTypeSystem;
impl TypeSystem for AutomationTypeSystem
{
    fn key() -> TypeSystemName
    {
        TypeSystemName::Automation
    }

    /// Gets the type system pointer from a ComItf.
    fn get_ptr<I: ?Sized>(itf: &ComItf<I>) -> Option<crate::raw::InterfacePtr<Self, I>>
    {
        itf.automation_ptr
    }

    /// Constructs a ComItf from a pointer.
    fn wrap_ptr<I: ?Sized>(ptr: crate::raw::InterfacePtr<Self, I>) -> ComItf<I>
    {
        ComItf {
            automation_ptr: Some(ptr),
            raw_ptr: None,
            phantom: std::marker::PhantomData,
        }
    }
}

/// Raw type system.
#[derive(Clone, Copy)]
pub struct RawTypeSystem;
impl TypeSystem for RawTypeSystem
{
    fn key() -> TypeSystemName
    {
        TypeSystemName::Raw
    }

    /// Gets the type system pointer from a ComItf.
    fn get_ptr<I: ?Sized>(itf: &ComItf<I>) -> Option<crate::raw::InterfacePtr<Self, I>>
    {
        itf.raw_ptr
    }

    /// Constructs a ComItf from a pointer.
    fn wrap_ptr<I: ?Sized>(ptr: crate::raw::InterfacePtr<Self, I>) -> ComItf<I>
    {
        ComItf {
            automation_ptr: None,
            raw_ptr: Some(ptr),
            phantom: std::marker::PhantomData,
        }
    }
}

/// Defines a type that has identical representation for both input and output directions.
pub trait ForeignType
{
    /// The name of the type.
    fn type_name() -> &'static str;
    fn indirection_level() -> u32
    {
        0
    }
}

/// Defines a type that may be used as a parameter type in Intercom interfaces.
///
/// # Safety
///
/// Implementing this trait allows Intercom to use the type as an input type.
/// This trait will be used within the code generated in the procedural macros.
/// It is important to ensure this trait is implemented in such a way that its
/// use in the macros is sound.
pub unsafe trait ExternInput<TS: TypeSystem>: Sized
{
    type ForeignType: ForeignType;

    type Lease;

    /// # Safety
    ///
    /// The returned `ForeignType` value is valid only as long as the `Lease`
    /// is held.
    unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>;

    type Owned;

    /// # Safety
    ///
    /// The validity of the returned `Owned` value depends on the source type.
    /// In general it shouldn't be used past the lifetime of the `source`
    /// reference.
    unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>;
}

/// Defines a type that may be used as an output type in Intercom interfaces.
///
/// # Safety
///
/// Implementing this trait allows Intercom to use the type as an output type.
/// This trait will be used within the code generated in the procedural macros.
/// It is important to ensure this trait is implemented in such a way that its
/// use in the macros is sound.
pub unsafe trait ExternOutput<TS: TypeSystem>: Sized
{
    type ForeignType: ForeignType;

    fn into_foreign_output(self) -> ComResult<Self::ForeignType>;

    /// # Safety
    ///
    /// The source ownership is transferred to the function invoker. In case of
    /// pointers, the function (or the `Self` type) is given the ownership of
    /// the memory. The caller must ensure that it owns the source parameter
    /// and is allowed to pass the ownership in this way.
    unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>;

    /// # Safety
    ///
    /// The source ownership is transferred to the function invoker. In case of
    /// pointers, the function (or the `Self` type) is given the ownership of
    /// the memory. The caller must ensure that it owns the source parameter
    /// and is allowed to pass the ownership in this way.
    unsafe fn drop_foreign_output(source: Self::ForeignType)
    {
        // Default implementation just converts this back to the original.
        //
        // The `from_foreign_output` is supposed to ensure unused memory isn't leaked and dropping
        // the return value will clean up the remaining memory.
        //
        // Type-specific implementation can clean up the source memory without going through the
        // trouble of creating  new `Self` value.
        let _ = Self::from_foreign_output(source);
    }
}

/// Defines a type that may be used as a parameter type in Intercom interfaces.
///
/// # Safety
///
/// Implementing this trait allows Intercom to use the type as an input type.
/// This trait will be used within the code generated in the procedural macros.
/// It is important to ensure this trait is implemented in such a way that its
/// use in the macros is sound.
pub unsafe trait InfallibleExternInput<TS: TypeSystem>: Sized
{
    type ForeignType: ForeignType;

    type Lease;

    /// # Safety
    ///
    /// The returned `ForeignType` value is valid only as long as the `Lease`
    /// is held.
    unsafe fn into_foreign_parameter(self) -> (Self::ForeignType, Self::Lease);

    type Owned;

    /// # Safety
    ///
    /// The validity of the returned `Owned` value depends on the source type.
    /// In general it shouldn't be used past the lifetime of the `source`
    /// reference.
    unsafe fn from_foreign_parameter(source: Self::ForeignType) -> Self::Owned;
}

/// Defines a type that may be used as an output type in Intercom interfaces.
///
/// # Safety
///
/// Implementing this trait allows Intercom to use the type as an output type.
/// This trait will be used within the code generated in the procedural macros.
/// It is important to ensure this trait is implemented in such a way that its
/// use in the macros is sound.
pub unsafe trait InfallibleExternOutput<TS: TypeSystem>: Sized
{
    type ForeignType: ForeignType;

    fn into_foreign_output(self) -> Self::ForeignType;

    /// # Safety
    ///
    /// The source ownership is transferred to the function invoker. In case of
    /// pointers, the function (or the `Self` type) is given the ownership of
    /// the memory. The caller must ensure that it owns the source parameter
    /// and is allowed to pass the ownership in this way.
    unsafe fn from_foreign_output(source: Self::ForeignType) -> Self;
}

/// Holds a conversion result and returns it back to the original type
pub struct OutputGuard<TS, TType>
where
    TS: TypeSystem,
    TType: ExternOutput<TS>,
{
    value: std::mem::ManuallyDrop<TType::ForeignType>,
}

impl<TS, TType> OutputGuard<TS, TType>
where
    TS: TypeSystem,
    TType: ExternOutput<TS>,
{
    pub fn wrap(value: TType::ForeignType) -> OutputGuard<TS, TType>
    {
        OutputGuard {
            value: std::mem::ManuallyDrop::new(value),
        }
    }

    pub fn consume(self) -> TType::ForeignType
    {
        unsafe {
            let value = std::ptr::read(&self.value);
            std::mem::forget(self);
            std::mem::ManuallyDrop::into_inner(value)
        }
    }
}

impl<TS, TType> Drop for OutputGuard<TS, TType>
where
    TS: TypeSystem,
    TType: ExternOutput<TS>,
{
    fn drop(&mut self)
    {
        unsafe {
            let v = std::mem::ManuallyDrop::take(&mut self.value);
            TType::drop_foreign_output(v);
        }
    }
}

/// A quick macro for implementing ExternInput/etc. for various basic types
/// that should represent themselves.
macro_rules! self_extern {
    ( $t:ty ) => {
        impl ForeignType for $t
        {
            /// The default name is the name of the type.
            fn type_name() -> &'static str
            {
                stringify!($t)
            }
        }

        unsafe impl<TS: TypeSystem> ExternInput<TS> for $t
        {
            type ForeignType = $t;
            type Lease = ();
            unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, ())>
            {
                Ok((self, ()))
            }

            type Owned = Self;
            unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
            {
                Ok(source)
            }
        }

        unsafe impl<TS: TypeSystem> ExternOutput<TS> for $t
        {
            type ForeignType = $t;
            fn into_foreign_output(self) -> ComResult<Self::ForeignType>
            {
                Ok(self)
            }

            unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
            {
                Ok(source)
            }
        }

        unsafe impl<TS: TypeSystem> InfallibleExternInput<TS> for $t
        {
            type ForeignType = $t;
            type Lease = ();
            unsafe fn into_foreign_parameter(self) -> (Self::ForeignType, ())
            {
                (self, ())
            }

            type Owned = Self;
            unsafe fn from_foreign_parameter(source: Self::ForeignType) -> Self::Owned
            {
                source
            }
        }

        unsafe impl<TS: TypeSystem> InfallibleExternOutput<TS> for $t
        {
            type ForeignType = $t;
            fn into_foreign_output(self) -> Self::ForeignType
            {
                self
            }

            unsafe fn from_foreign_output(source: Self::ForeignType) -> Self
            {
                source
            }
        }
    };
}

// Define all types that should have built-in Self extern type.
self_extern!(());
self_extern!(i8);
self_extern!(i16);
self_extern!(i32);
self_extern!(i64);
self_extern!(isize);
self_extern!(u8);
self_extern!(u16);
self_extern!(u32);
self_extern!(u64);
self_extern!(usize);
self_extern!(f32);
self_extern!(f64);
self_extern!(bool);

use crate::raw::HRESULT;
self_extern!(HRESULT);

use crate::GUID;
self_extern!(GUID);

self_extern!(TypeSystemName);

self_extern!(std::ffi::c_void);

macro_rules! extern_ptr {
    ( $mut:tt ) => {
        unsafe impl<TS: TypeSystem, TPtr: ForeignType + ?Sized> ExternOutput<TS> for *$mut TPtr
        {
            type ForeignType = Self;
            fn into_foreign_output(self) -> ComResult<Self::ForeignType>
            {
                Ok(self)
            }

            unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
            {
                Ok(source)
            }
        }

        unsafe impl<TS: TypeSystem, TPtr: ForeignType + ?Sized> ExternInput<TS> for *$mut TPtr
        {
            type ForeignType = Self;
            type Lease = ();
            unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, ())>
            {
                Ok((self, ()))
            }

            type Owned = Self;
            unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
            {
                Ok(source)
            }
        }

        unsafe impl<TS: TypeSystem, TPtr: ForeignType + ?Sized> InfallibleExternOutput<TS> for *$mut TPtr
        {
            type ForeignType = Self;
            fn into_foreign_output(self) -> Self::ForeignType
            {
                self
            }

            unsafe fn from_foreign_output(source: Self::ForeignType) -> Self
            {
                source
            }
        }

        unsafe impl<TS: TypeSystem, TPtr: ForeignType + ?Sized> InfallibleExternInput<TS> for *$mut TPtr
        {
            type ForeignType = Self;
            type Lease = ();
            unsafe fn into_foreign_parameter(self) -> (Self::ForeignType, ())
            {
                (self, ())
            }

            type Owned = Self;
            unsafe fn from_foreign_parameter(source: Self::ForeignType) -> Self::Owned
            {
                source
            }
        }

        impl<TPtr: ForeignType + ?Sized> ForeignType for *$mut TPtr
        {
            fn type_name() -> &'static str
            {
                <TPtr as ForeignType>::type_name()
            }

            fn indirection_level() -> u32
            {
                <TPtr as ForeignType>::indirection_level() + 1
            }
        }
    }
}

extern_ptr!(mut);
extern_ptr!(const);

/// Defines the uninitialized values for out parameters when calling into
/// Intercom interfaces.
pub trait ExternDefault
{
    /// # Safety
    ///
    /// This results in zeroed values. This should only be used for types that
    /// are okay being zeroed (mainly `#[repr(C)]` types).
    unsafe fn extern_default() -> Self;
}

impl<T> ExternDefault for T
{
    unsafe fn extern_default() -> Self
    {
        std::mem::zeroed()
    }
}
<commit_msg>Improve OutputGuard documentation<commit_after>use crate::prelude::*;
use crate::ComItf;

#[derive(Debug, Clone, Copy, Hash, PartialOrd, PartialEq)]
#[repr(C)]
pub enum TypeSystemName
{
    Automation = 0,
    Raw = 1,
}

impl TypeSystemName
{
    pub fn get_ptr<I: ?Sized>(self, itf: &ComItf<I>) -> crate::raw::RawComPtr
    {
        let opt = match self {
            TypeSystemName::Automation => AutomationTypeSystem::get_ptr(itf).map(|p| p.ptr),
            TypeSystemName::Raw => RawTypeSystem::get_ptr(itf).map(|p| p.ptr),
        };

        match opt {
            Some(ptr) => ptr.as_ptr(),
            None => std::ptr::null_mut(),
        }
    }
}

/// Common trait for type systems.
pub trait TypeSystem: Clone + Copy
{
    const AUTOMATION: TypeSystemName = TypeSystemName::Automation;
    const RAW: TypeSystemName = TypeSystemName::Raw;

    fn key() -> TypeSystemName;

    /// Gets the type system pointer from a ComItf.
    fn get_ptr<I: ?Sized>(itf: &ComItf<I>) -> Option<crate::raw::InterfacePtr<Self, I>>;

    /// Constructs a ComItf from a pointer.
    fn wrap_ptr<I: ?Sized>(ptr: crate::raw::InterfacePtr<Self, I>) -> ComItf<I>;
}

/// Automation type system.
#[derive(Clone, Copy)]
pub struct AutomationTypeSystem;
impl TypeSystem for AutomationTypeSystem
{
    fn key() -> TypeSystemName
    {
        TypeSystemName::Automation
    }

    /// Gets the type system pointer from a ComItf.
    fn get_ptr<I: ?Sized>(itf: &ComItf<I>) -> Option<crate::raw::InterfacePtr<Self, I>>
    {
        itf.automation_ptr
    }

    /// Constructs a ComItf from a pointer.
    fn wrap_ptr<I: ?Sized>(ptr: crate::raw::InterfacePtr<Self, I>) -> ComItf<I>
    {
        ComItf {
            automation_ptr: Some(ptr),
            raw_ptr: None,
            phantom: std::marker::PhantomData,
        }
    }
}

/// Raw type system.
#[derive(Clone, Copy)]
pub struct RawTypeSystem;
impl TypeSystem for RawTypeSystem
{
    fn key() -> TypeSystemName
    {
        TypeSystemName::Raw
    }

    /// Gets the type system pointer from a ComItf.
    fn get_ptr<I: ?Sized>(itf: &ComItf<I>) -> Option<crate::raw::InterfacePtr<Self, I>>
    {
        itf.raw_ptr
    }

    /// Constructs a ComItf from a pointer.
    fn wrap_ptr<I: ?Sized>(ptr: crate::raw::InterfacePtr<Self, I>) -> ComItf<I>
    {
        ComItf {
            automation_ptr: None,
            raw_ptr: Some(ptr),
            phantom: std::marker::PhantomData,
        }
    }
}

/// Defines a type that has identical representation for both input and output directions.
pub trait ForeignType
{
    /// The name of the type.
    fn type_name() -> &'static str;
    fn indirection_level() -> u32
    {
        0
    }
}

/// Defines a type that may be used as a parameter type in Intercom interfaces.
///
/// # Safety
///
/// Implementing this trait allows Intercom to use the type as an input type.
/// This trait will be used within the code generated in the procedural macros.
/// It is important to ensure this trait is implemented in such a way that its
/// use in the macros is sound.
pub unsafe trait ExternInput<TS: TypeSystem>: Sized
{
    type ForeignType: ForeignType;

    type Lease;

    /// # Safety
    ///
    /// The returned `ForeignType` value is valid only as long as the `Lease`
    /// is held.
    unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>;

    type Owned;

    /// # Safety
    ///
    /// The validity of the returned `Owned` value depends on the source type.
    /// In general it shouldn't be used past the lifetime of the `source`
    /// reference.
    unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>;
}

/// Defines a type that may be used as an output type in Intercom interfaces.
///
/// # Safety
///
/// Implementing this trait allows Intercom to use the type as an output type.
/// This trait will be used within the code generated in the procedural macros.
/// It is important to ensure this trait is implemented in such a way that its
/// use in the macros is sound.
pub unsafe trait ExternOutput<TS: TypeSystem>: Sized
{
    type ForeignType: ForeignType;

    fn into_foreign_output(self) -> ComResult<Self::ForeignType>;

    /// # Safety
    ///
    /// The source ownership is transferred to the function invoker. In case of
    /// pointers, the function (or the `Self` type) is given the ownership of
    /// the memory. The caller must ensure that it owns the source parameter
    /// and is allowed to pass the ownership in this way.
    unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>;

    /// # Safety
    ///
    /// The source ownership is transferred to the function invoker. In case of
    /// pointers, the function (or the `Self` type) is given the ownership of
    /// the memory. The caller must ensure that it owns the source parameter
    /// and is allowed to pass the ownership in this way.
    unsafe fn drop_foreign_output(source: Self::ForeignType)
    {
        // Default implementation just converts this back to the original.
        //
        // The `from_foreign_output` is supposed to ensure unused memory isn't leaked and dropping
        // the return value will clean up the remaining memory.
        //
        // Type-specific implementation can clean up the source memory without going through the
        // trouble of creating  new `Self` value.
        let _ = Self::from_foreign_output(source);
    }
}

/// Defines a type that may be used as a parameter type in Intercom interfaces.
///
/// # Safety
///
/// Implementing this trait allows Intercom to use the type as an input type.
/// This trait will be used within the code generated in the procedural macros.
/// It is important to ensure this trait is implemented in such a way that its
/// use in the macros is sound.
pub unsafe trait InfallibleExternInput<TS: TypeSystem>: Sized
{
    type ForeignType: ForeignType;

    type Lease;

    /// # Safety
    ///
    /// The returned `ForeignType` value is valid only as long as the `Lease`
    /// is held.
    unsafe fn into_foreign_parameter(self) -> (Self::ForeignType, Self::Lease);

    type Owned;

    /// # Safety
    ///
    /// The validity of the returned `Owned` value depends on the source type.
    /// In general it shouldn't be used past the lifetime of the `source`
    /// reference.
    unsafe fn from_foreign_parameter(source: Self::ForeignType) -> Self::Owned;
}

/// Defines a type that may be used as an output type in Intercom interfaces.
///
/// # Safety
///
/// Implementing this trait allows Intercom to use the type as an output type.
/// This trait will be used within the code generated in the procedural macros.
/// It is important to ensure this trait is implemented in such a way that its
/// use in the macros is sound.
pub unsafe trait InfallibleExternOutput<TS: TypeSystem>: Sized
{
    type ForeignType: ForeignType;

    fn into_foreign_output(self) -> Self::ForeignType;

    /// # Safety
    ///
    /// The source ownership is transferred to the function invoker. In case of
    /// pointers, the function (or the `Self` type) is given the ownership of
    /// the memory. The caller must ensure that it owns the source parameter
    /// and is allowed to pass the ownership in this way.
    unsafe fn from_foreign_output(source: Self::ForeignType) -> Self;
}

/// Holds a conversion result foreign value and cleans it up unless consumed
pub struct OutputGuard<TS, TType>
where
    TS: TypeSystem,
    TType: ExternOutput<TS>,
{
    value: std::mem::ManuallyDrop<TType::ForeignType>,
}

impl<TS, TType> OutputGuard<TS, TType>
where
    TS: TypeSystem,
    TType: ExternOutput<TS>,
{
    /// Wrap a foreign value in the guard.
    pub fn wrap(value: TType::ForeignType) -> OutputGuard<TS, TType>
    {
        OutputGuard {
            value: std::mem::ManuallyDrop::new(value),
        }
    }

    /// Consume the guard to acquire the final value and giving up on having to clean it later.
    pub fn consume(self) -> TType::ForeignType
    {
        unsafe {
            // Read the value out of the guard and forget the guard to avoid
            // dropping it, which would clean the value.
            let value = std::ptr::read(&self.value);
            std::mem::forget(self);
            std::mem::ManuallyDrop::into_inner(value)
        }
    }
}

impl<TS, TType> Drop for OutputGuard<TS, TType>
where
    TS: TypeSystem,
    TType: ExternOutput<TS>,
{
    fn drop(&mut self)
    {
        unsafe {
            // Clean the value on drop..
            let v = std::mem::ManuallyDrop::take(&mut self.value);
            TType::drop_foreign_output(v);
        }
    }
}

/// A quick macro for implementing ExternInput/etc. for various basic types
/// that should represent themselves.
macro_rules! self_extern {
    ( $t:ty ) => {
        impl ForeignType for $t
        {
            /// The default name is the name of the type.
            fn type_name() -> &'static str
            {
                stringify!($t)
            }
        }

        unsafe impl<TS: TypeSystem> ExternInput<TS> for $t
        {
            type ForeignType = $t;
            type Lease = ();
            unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, ())>
            {
                Ok((self, ()))
            }

            type Owned = Self;
            unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
            {
                Ok(source)
            }
        }

        unsafe impl<TS: TypeSystem> ExternOutput<TS> for $t
        {
            type ForeignType = $t;
            fn into_foreign_output(self) -> ComResult<Self::ForeignType>
            {
                Ok(self)
            }

            unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
            {
                Ok(source)
            }
        }

        unsafe impl<TS: TypeSystem> InfallibleExternInput<TS> for $t
        {
            type ForeignType = $t;
            type Lease = ();
            unsafe fn into_foreign_parameter(self) -> (Self::ForeignType, ())
            {
                (self, ())
            }

            type Owned = Self;
            unsafe fn from_foreign_parameter(source: Self::ForeignType) -> Self::Owned
            {
                source
            }
        }

        unsafe impl<TS: TypeSystem> InfallibleExternOutput<TS> for $t
        {
            type ForeignType = $t;
            fn into_foreign_output(self) -> Self::ForeignType
            {
                self
            }

            unsafe fn from_foreign_output(source: Self::ForeignType) -> Self
            {
                source
            }
        }
    };
}

// Define all types that should have built-in Self extern type.
self_extern!(());
self_extern!(i8);
self_extern!(i16);
self_extern!(i32);
self_extern!(i64);
self_extern!(isize);
self_extern!(u8);
self_extern!(u16);
self_extern!(u32);
self_extern!(u64);
self_extern!(usize);
self_extern!(f32);
self_extern!(f64);
self_extern!(bool);

use crate::raw::HRESULT;
self_extern!(HRESULT);

use crate::GUID;
self_extern!(GUID);

self_extern!(TypeSystemName);

self_extern!(std::ffi::c_void);

macro_rules! extern_ptr {
    ( $mut:tt ) => {
        unsafe impl<TS: TypeSystem, TPtr: ForeignType + ?Sized> ExternOutput<TS> for *$mut TPtr
        {
            type ForeignType = Self;
            fn into_foreign_output(self) -> ComResult<Self::ForeignType>
            {
                Ok(self)
            }

            unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
            {
                Ok(source)
            }
        }

        unsafe impl<TS: TypeSystem, TPtr: ForeignType + ?Sized> ExternInput<TS> for *$mut TPtr
        {
            type ForeignType = Self;
            type Lease = ();
            unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, ())>
            {
                Ok((self, ()))
            }

            type Owned = Self;
            unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
            {
                Ok(source)
            }
        }

        unsafe impl<TS: TypeSystem, TPtr: ForeignType + ?Sized> InfallibleExternOutput<TS> for *$mut TPtr
        {
            type ForeignType = Self;
            fn into_foreign_output(self) -> Self::ForeignType
            {
                self
            }

            unsafe fn from_foreign_output(source: Self::ForeignType) -> Self
            {
                source
            }
        }

        unsafe impl<TS: TypeSystem, TPtr: ForeignType + ?Sized> InfallibleExternInput<TS> for *$mut TPtr
        {
            type ForeignType = Self;
            type Lease = ();
            unsafe fn into_foreign_parameter(self) -> (Self::ForeignType, ())
            {
                (self, ())
            }

            type Owned = Self;
            unsafe fn from_foreign_parameter(source: Self::ForeignType) -> Self::Owned
            {
                source
            }
        }

        impl<TPtr: ForeignType + ?Sized> ForeignType for *$mut TPtr
        {
            fn type_name() -> &'static str
            {
                <TPtr as ForeignType>::type_name()
            }

            fn indirection_level() -> u32
            {
                <TPtr as ForeignType>::indirection_level() + 1
            }
        }
    }
}

extern_ptr!(mut);
extern_ptr!(const);

/// Defines the uninitialized values for out parameters when calling into
/// Intercom interfaces.
pub trait ExternDefault
{
    /// # Safety
    ///
    /// This results in zeroed values. This should only be used for types that
    /// are okay being zeroed (mainly `#[repr(C)]` types).
    unsafe fn extern_default() -> Self;
}

impl<T> ExternDefault for T
{
    unsafe fn extern_default() -> Self
    {
        std::mem::zeroed()
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate irc;

use std::net::TcpStream;
use std::io::{Write, BufRead, BufReader};

use irc::protocol::message::{IrcMessage, Message, Body};
use irc::protocol::command::{Command, UserCommand, NickCommand, JoinCommand, PongCommand};
use irc::protocol::reply::ReplyCode;

fn main() {
    env_logger::init().unwrap();

    let server_addr = "irc.mozilla.org:6667";

    info!("Connecting to {:?}", server_addr);
    let mut stream = TcpStream::connect(server_addr).unwrap();
    let bufreader = BufReader::new(stream.try_clone().unwrap());

    let username = "rust_irc_test";
    let nickname = username;

    let usercmd = UserCommand::new(username, 0, username);
    let nickcmd = NickCommand::new(nickname);

    {
        let usermsg = Message::new(None, Body::command(usercmd));
        let nickmsg = Message::new(None, Body::command(nickcmd));

        info!("Authorizing: sending {:?}", usermsg);
        write!(stream, "{}\r\n", usermsg).unwrap();

        info!("Authorizing: sending {:?}", nickmsg);
        write!(stream, "{}\r\n", nickmsg).unwrap();
    }

    let mut lines = bufreader.lines();

    {
        // Waiting for MOTD_START
        while let Some(line) = lines.next() {
            let line = line.unwrap();

            let parsed = Message::from_str(line.trim()).unwrap();
            trace!("{:?}", parsed);

            if let &Body::Reply(ref rpl) = parsed.body() {
                if let ReplyCode::RPL_MOTDSTART = rpl.code() {
                    let params = rpl.parameters().collect::<Vec<&str>>();
                    println!("-*- {}", params.connect(" "));
                    break;
                }
            }
        }

        // Printing MOTD
        while let Some(line) = lines.next() {
            let line = line.unwrap();

            let parsed = Message::from_str(line.trim()).unwrap();
            trace!("{:?}", parsed);

            if let &Body::Reply(ref rpl) = parsed.body() {
                match rpl.code() {
                    ReplyCode::RPL_MOTD => {
                        let params = rpl.parameters().collect::<Vec<&str>>();
                        println!("-*- {}", params.connect(" "));
                    },
                    ReplyCode::RPL_ENDOFMOTD => {
                        let params = rpl.parameters().collect::<Vec<&str>>();
                        println!("-*- {}", params.connect(" "));
                        break;
                    },
                    _ => {}
                }
            }
        }
    }

    {
        // Join channel
        let joincmd = JoinCommand::new("#rust", None);
        let joinmsg = Message::new(None, Body::command(joincmd));

        info!("Join channel: Sending {:?}", joinmsg);
        write!(stream, "{}\r\n", joinmsg).unwrap();
    }

    // Prints conversation
    for line in lines {
        let line = line.unwrap();

        let parsed = Message::from_str(line.trim()).unwrap();
        trace!("{:?}", parsed);

        if let &Body::Command(ref cmd) = parsed.body() {
            match cmd {
                &Command::Privmsg(ref privmsg) => {
                    let prefix = parsed.prefix().unwrap();

                    let name = match prefix.find('!') {
                        None => prefix,
                        Some(idx) => &prefix[..idx],
                    };

                    println!("-*- < {} > {}", name, privmsg.message());
                },
                &Command::Ping(ref ping) => {
                    debug!("Received ping {:?}", ping);
                    let pong = PongCommand::new(ping.servers().get());
                    debug!("Sending pong {:?}", pong);
                    write!(stream, "{}\r\n", Message::new(None, Body::command(pong))).unwrap();
                },
                _ => {}
            }
        }
    }
}
<commit_msg>added command line argument, fixed bugs<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate irc;

use std::net::TcpStream;
use std::io::{self, Write, BufRead, BufReader};
use std::thread;
use std::env;

use irc::protocol::message::{IrcMessage, Message, Body};
use irc::protocol::command::{Command, UserCommand, NickCommand, JoinCommand, PongCommand, PrivmsgCommand, QuitCommand};
use irc::protocol::reply::ReplyCode;

fn main() {
    env_logger::init().unwrap();

    let username: String = env::args().skip(1).next().expect("You have to provide a username").clone();
    let server_addr = "irc.mozilla.org:6667";

    println!("Logging to {:?} as {:?}", server_addr, username);

    info!("Connecting to {:?}", server_addr);
    let mut stream = TcpStream::connect(server_addr).unwrap();
    let bufreader = BufReader::new(stream.try_clone().unwrap());

    let nickname = &username[..];

    {
        let usercmd = UserCommand::new(&username[..], 0, &username[..]);
        let nickcmd = NickCommand::new(nickname);
        let usermsg = Message::new(None, Body::command(usercmd));
        let nickmsg = Message::new(None, Body::command(nickcmd));

        info!("Authorizing: sending {:?}", usermsg);
        write!(stream, "{}\r\n", usermsg).unwrap();

        info!("Authorizing: sending {:?}", nickmsg);
        write!(stream, "{}\r\n", nickmsg).unwrap();
    }

    let mut lines = bufreader.lines();

    {
        // Waiting for MOTD_START
        while let Some(line) = lines.next() {
            let line = line.unwrap();

            let parsed = Message::from_str(line.trim()).unwrap();
            trace!("{:?}", parsed);

            if let &Body::Reply(ref rpl) = parsed.body() {
                if let ReplyCode::RPL_MOTDSTART = rpl.code() {
                    let params = rpl.parameters().collect::<Vec<&str>>();
                    println!("-*- {}", params.connect(" "));
                    break;
                } else if let ReplyCode::ERR_NICKNAMEINUSE = rpl.code() {
                    panic!("Nickname {:?} already in use", nickname);
                }
            } else if let &Body::Command(ref cmd) = parsed.body() {
                if let &Command::Notice(ref notice) = cmd {
                    println!("-*- Notice: {}", notice.message());
                }
            }
        }

        // Printing MOTD
        while let Some(line) = lines.next() {
            let line = line.unwrap();

            let parsed = Message::from_str(line.trim()).unwrap();
            trace!("{:?}", parsed);

            if let &Body::Reply(ref rpl) = parsed.body() {
                match rpl.code() {
                    ReplyCode::RPL_MOTD => {
                        let params = rpl.parameters().collect::<Vec<&str>>();
                        println!("-*- {}", params.connect(" "));
                    },
                    ReplyCode::RPL_ENDOFMOTD => {
                        let params = rpl.parameters().collect::<Vec<&str>>();
                        println!("-*- {}", params.connect(" "));
                        break;
                    },
                    _ => {}
                }
            }
        }
    }

    {
        // Join channel
        let joincmd = JoinCommand::new("#rust", None);
        let joinmsg = Message::new(None, Body::command(joincmd));

        info!("Join channel: Sending {:?}", joinmsg);
        write!(stream, "{}\r\n", joinmsg).unwrap();
    }

    let mut writeable_stream = stream.try_clone().unwrap();
    let cloned_username = username.clone();
    thread::spawn(move|| {
        let bufstdin = BufReader::new(io::stdin());
        for line in bufstdin.lines() {
            let line = line.unwrap();
            let msg = line.trim();

            if !msg.is_empty() {
                if msg.starts_with("/") {
                    let mut sp = msg.splitn(2, ' ');
                    let cmd = sp.next().unwrap();
                    let cmd = (&cmd[1..]).chars().flat_map(|x| x.to_uppercase()).collect::<String>();

                    match &cmd[..] {
                        "QUIT" => {
                            let quitcmd = QuitCommand::new(sp.next());
                            let msg = Message::new(None, Body::command(quitcmd));
                            trace!("Quit: Sending {:?}", msg);
                            write!(writeable_stream, "{}\r\n", msg).unwrap();
                        },
                        _ => {
                            error!("Unknown command {}", cmd);
                        }
                    }
                } else {
                    let privmsg = PrivmsgCommand::new("#rust", msg);
                    println!("-*- < {} > {}", cloned_username, msg);
                    let msg = Message::new(None, Body::command(privmsg));
                    trace!("Privmsg: Sending {:?}", msg);
                    write!(writeable_stream, "{}\r\n", msg).unwrap();
                }
            }
        }
    });

    // Prints conversation
    for line in lines {
        let line = line.unwrap();

        let parsed = Message::from_str(line.trim()).unwrap();
        trace!("{:?}", parsed);

        if let &Body::Command(ref cmd) = parsed.body() {
            match cmd {
                &Command::Privmsg(ref privmsg) => {
                    let prefix = parsed.prefix().unwrap();

                    let name = match prefix.find('!') {
                        None => prefix,
                        Some(idx) => &prefix[..idx],
                    };

                    println!("-*- < {} > {}", name, privmsg.message());
                },
                &Command::Ping(ref ping) => {
                    debug!("Received ping {:?}", ping);
                    let pong = PongCommand::new(ping.servers().get());
                    debug!("Sending pong {:?}", pong);
                    write!(stream, "{}\r\n", Message::new(None, Body::command(pong))).unwrap();
                },
                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new(env!("CARGO"));

	cmd.env("CARGO_TERM_COLOR", "always");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	if target.target_arch() == "aarch64" {
		cmd.arg("--features");
		cmd.arg("aarch64-qemu-stdout");
	}

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = vec!["-Zmutable-noalias=no".to_string()];
	let outer_rustflags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer rustflags to command
		rustflags.push(outer_rustflags);
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer rustflags before adding them to the command.
		if !outer_rustflags.is_empty() {
			let flags = outer_rustflags
				.split('\x1f')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("CARGO_ENCODED_RUSTFLAGS", rustflags.join("\x1f"));

	let status = cmd.status().expect("failed to start kernel build");
	assert!(status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	let lib = lib_location.join("libhermit.a");

	rename_symbol("rust_begin_unwind", &lib);
	rename_symbol("rust_oom", &lib);

	#[cfg(feature = "mem")]
	{
		for symbol in ["memcpy", "memmove", "memset", "memcmp", "bcmp"] {
			rename_symbol(symbol, &lib);
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	// HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

/// Kernel and user space has its own versions of panic handler, oom handler, memcpy, memset, etc,
/// Consequently, we rename the functions in the libos to avoid collisions.
/// In addition, it provides us the offer to create a optimized version of memcpy
/// in user space.
fn rename_symbol(symbol: impl AsRef<OsStr>, lib: impl AsRef<Path>) {
	// Get access to llvm tools shipped in the llvm-tools-preview rustup component
	let llvm_tools = match llvm_tools::LlvmTools::new() {
		Ok(tools) => tools,
		Err(llvm_tools::Error::NotFound) => {
			eprintln!("Error: llvm-tools not found");
			eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
			eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
			process::exit(1);
		}
		Err(err) => {
			eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
			process::exit(1);
		}
	};

	// Retrieve path of llvm-objcopy
	let llvm_objcopy = llvm_tools
		.tool(&llvm_tools::exe("llvm-objcopy"))
		.expect("llvm-objcopy not found in llvm-tools");

	// Rename symbols
	let arg = IntoIterator::into_iter([symbol.as_ref(), "=kernel-".as_ref(), symbol.as_ref()])
		.collect::<OsString>();
	let status = Command::new(llvm_objcopy)
		.arg("--redefine-sym")
		.arg(arg)
		.arg(lib.as_ref())
		.status()
		.expect("failed to execute llvm-objcopy");
	assert!(status.success(), "llvm-objcopy was not successful");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let status = Command::new(env!("CARGO"))
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.status()
			.expect("failed to start kernel download");
		assert!(
			status.success(),
			"Unable to download rusty-hermit. Is cargo-download installed?"
		);
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(is_not_ignored)
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<commit_msg>Decouple libhermit-rs toolchain<commit_after>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	cmd.env_remove("RUSTUP_TOOLCHAIN");
	if option_env!("RUSTC_WORKSPACE_WRAPPER")
		.unwrap_or_default()
		.ends_with("clippy-driver")
	{
		cmd.env("RUSTC_WORKSPACE_WRAPPER", "clippy-driver");
	}

	cmd.env("CARGO_TERM_COLOR", "always");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	if target.target_arch() == "aarch64" {
		cmd.arg("--features");
		cmd.arg("aarch64-qemu-stdout");
	}

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = vec!["-Zmutable-noalias=no".to_string()];
	let outer_rustflags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer rustflags to command
		rustflags.push(outer_rustflags);
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer rustflags before adding them to the command.
		if !outer_rustflags.is_empty() {
			let flags = outer_rustflags
				.split('\x1f')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("CARGO_ENCODED_RUSTFLAGS", rustflags.join("\x1f"));

	let status = cmd.status().expect("failed to start kernel build");
	assert!(status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	let lib = lib_location.join("libhermit.a");

	rename_symbol("rust_begin_unwind", &lib);
	rename_symbol("rust_oom", &lib);

	#[cfg(feature = "mem")]
	{
		for symbol in ["memcpy", "memmove", "memset", "memcmp", "bcmp"] {
			rename_symbol(symbol, &lib);
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	// HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

/// Kernel and user space has its own versions of panic handler, oom handler, memcpy, memset, etc,
/// Consequently, we rename the functions in the libos to avoid collisions.
/// In addition, it provides us the offer to create a optimized version of memcpy
/// in user space.
fn rename_symbol(symbol: impl AsRef<OsStr>, lib: impl AsRef<Path>) {
	// Get access to llvm tools shipped in the llvm-tools-preview rustup component
	let llvm_tools = match llvm_tools::LlvmTools::new() {
		Ok(tools) => tools,
		Err(llvm_tools::Error::NotFound) => {
			eprintln!("Error: llvm-tools not found");
			eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
			eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
			process::exit(1);
		}
		Err(err) => {
			eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
			process::exit(1);
		}
	};

	// Retrieve path of llvm-objcopy
	let llvm_objcopy = llvm_tools
		.tool(&llvm_tools::exe("llvm-objcopy"))
		.expect("llvm-objcopy not found in llvm-tools");

	// Rename symbols
	let arg = IntoIterator::into_iter([symbol.as_ref(), "=kernel-".as_ref(), symbol.as_ref()])
		.collect::<OsString>();
	let status = Command::new(llvm_objcopy)
		.arg("--redefine-sym")
		.arg(arg)
		.arg(lib.as_ref())
		.status()
		.expect("failed to execute llvm-objcopy");
	assert!(status.success(), "llvm-objcopy was not successful");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let status = Command::new(env!("CARGO"))
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.status()
			.expect("failed to start kernel download");
		assert!(
			status.success(),
			"Unable to download rusty-hermit. Is cargo-download installed?"
		);
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(is_not_ignored)
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<|endoftext|>


<commit_before>extern crate time;
extern crate rustc_serialize;

use rustc_serialize::json;

mod transaction;
mod account;

use account::*;

fn main() {
    use std::env;
    // Collect arguments into a vector
    let mut arguments = Vec::new();
    for argument in env::args() {
        arguments.push(argument);
    }
    let t = Transaction {
        amount: 100,
        recur_day: None,
        complete: true,
    };

    println!("{:?}", &t);
    let enc = json::encode(&t).unwrap();
    println!("{}", &enc);
    let dec: Transaction = json::decode(&enc).unwrap();
    println!("{:?}", dec);
}

<commit_msg>Remove testing code.<commit_after>extern crate time;
extern crate rustc_serialize;

use rustc_serialize::json;

mod transaction;
mod account;
mod system;

use account::*;

fn main() {
    use std::env;
    // Collect arguments into a vector
    let mut arguments = Vec::new();
    for argument in env::args() {
        arguments.push(argument);
    }
}

<|endoftext|>