<commit_before>use base64::write::EncoderWriter;
use indexmap::IndexMap;
use prometheus::proto::{MetricFamily, MetricType};
use prometheus::{Encoder, Error};
use std::io::Write;

/// The `LogEncoder` struct encodes Prometheus metrics in the format [`crates-io-heroku-metrics`]
/// expects metrics to be logged. This can be used to forward instance metrics to it, allowing them
/// to be scraped by the Rust infrastructure monitoring system.
///
/// The metrics are encoded in the format [Vector expects them][vector], and the list of metrics is
/// json-encoded and then base64-encoded. The whole thing is prefixed with a predefined string to
/// let [`crates-io-heroku-metrics`] find it easily.
///
/// This is needed mostly for crates.io hosted on Heroku. Deployments of crates.io on other
/// platforms shouldn't need this.
///
/// [`crates-io-heroku-metrics`]: https://github.com/rust-lang/crates-io-heroku-metrics
/// [vector]: https://vector.dev/docs/about/under-the-hood/architecture/data-model/metric/
#[derive(Debug, Clone, Copy)]
pub struct LogEncoder(());

impl LogEncoder {
    pub fn new() -> Self {
        Self(())
    }
}

impl Encoder for LogEncoder {
    fn encode<W: Write>(
        &self,
        families: &[MetricFamily],
        mut dest: &mut W,
    ) -> prometheus::Result<()> {
        let events = families_to_json_events(families);

        dest.write_all(b"crates-io-heroku-metrics:ingest ")?;
        let base64_dest = EncoderWriter::new(&mut dest, base64::STANDARD);
        serde_json::to_writer(base64_dest, &events).map_err(|e| Error::Msg(e.to_string()))?;
        dest.write_all(b"\n")?;

        Ok(())
    }

    fn format_type(&self) -> &str {
        "crates-io-heroku-metrics log encoding"
    }
}

fn families_to_json_events(families: &[MetricFamily]) -> Vec<VectorEvent<'_>> {
    let mut events = Vec::new();
    for family in families {
        for metric in family.get_metric() {
            let data = match family.get_field_type() {
                MetricType::COUNTER => VectorMetricData::Counter {
                    value: metric.get_counter().get_value(),
                },
                MetricType::GAUGE => VectorMetricData::Gauge {
                    value: metric.get_gauge().get_value(),
                },
                MetricType::HISTOGRAM => {
                    let histogram = metric.get_histogram();

                    // We need to convert from cumulative counts (used by the Prometheus library)
                    // to plain counts (used by Vector).
                    let mut buckets = Vec::new();
                    let mut last_cumulative_count = 0;
                    for bucket in histogram.get_bucket() {
                        buckets.push(VectorHistogramBucket {
                            upper_limit: bucket.get_upper_bound(),
                            count: bucket.get_cumulative_count() - last_cumulative_count,
                        });
                        last_cumulative_count = bucket.get_cumulative_count();
                    }

                    VectorMetricData::AggregatedHistogram {
                        count: histogram.get_sample_count(),
                        sum: histogram.get_sample_sum(),
                        buckets,
                    }
                }
                other => {
                    panic!("unsupported metric type: {:?}", other)
                }
            };
            events.push(VectorEvent {
                metric: VectorMetric {
                    data,
                    kind: "absolute",
                    name: family.get_name(),
                    tags: metric
                        .get_label()
                        .iter()
                        .map(|p| (p.get_name(), p.get_value()))
                        .collect(),
                },
            });
        }
    }
    events
}

#[derive(Serialize, Debug, PartialEq)]
struct VectorEvent<'a> {
    metric: VectorMetric<'a>,
}

#[derive(Serialize, Debug, PartialEq)]
struct VectorMetric<'a> {
    #[serde(flatten)]
    data: VectorMetricData,
    kind: &'a str,
    name: &'a str,
    tags: IndexMap<&'a str, &'a str>,
}

#[derive(Serialize, Debug, PartialEq)]
#[serde(rename_all = "snake_case")]
enum VectorMetricData {
    AggregatedHistogram {
        buckets: Vec<VectorHistogramBucket>,
        count: u64,
        sum: f64,
    },
    Counter {
        value: f64,
    },
    Gauge {
        value: f64,
    },
}

#[derive(Serialize, Debug, PartialEq)]
struct VectorHistogramBucket {
    upper_limit: f64,
    count: u64,
}

#[cfg(test)]
mod tests {
    use super::*;
    use anyhow::Error;
    use prometheus::{Histogram, HistogramOpts, IntCounter, IntGauge, IntGaugeVec, Opts, Registry};

    #[test]
    fn test_counter_to_json() -> Result<(), Error> {
        let counter =
            IntCounter::with_opts(Opts::new("sample_counter", "sample_counter help message"))?;
        let registry = Registry::new();
        registry.register(Box::new(counter.clone()))?;

        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::Counter { value: 0.0 },
                    kind: "absolute",
                    name: "sample_counter",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        counter.inc_by(42);
        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::Counter { value: 42.0 },
                    kind: "absolute",
                    name: "sample_counter",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        Ok(())
    }

    #[test]
    fn test_gauge_to_json() -> Result<(), Error> {
        let gauge = IntGauge::with_opts(Opts::new("sample_gauge", "sample_gauge help message"))?;
        let registry = Registry::new();
        registry.register(Box::new(gauge.clone()))?;

        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::Gauge { value: 0.0 },
                    kind: "absolute",
                    name: "sample_gauge",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        gauge.set(42);
        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::Gauge { value: 42.0 },
                    kind: "absolute",
                    name: "sample_gauge",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        Ok(())
    }

    #[test]
    fn test_histogram_to_json() -> Result<(), Error> {
        let histogram = Histogram::with_opts(HistogramOpts::new(
            "sample_histogram",
            "sample_histogram help message",
        ))?;
        let registry = Registry::new();
        registry.register(Box::new(histogram.clone()))?;

        let mut value = 0.0;
        while value < 11.0 {
            histogram.observe(value);
            value += 0.001;
        }

        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::AggregatedHistogram {
                        buckets: vec![
                            VectorHistogramBucket {
                                upper_limit: 0.005,
                                count: 6,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.01,
                                count: 4,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.025,
                                count: 15,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.05,
                                count: 25,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.1,
                                count: 50,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.25,
                                count: 150,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.5,
                                count: 250,
                            },
                            VectorHistogramBucket {
                                upper_limit: 1.0,
                                count: 500,
                            },
                            VectorHistogramBucket {
                                upper_limit: 2.5,
                                count: 1501,
                            },
                            VectorHistogramBucket {
                                upper_limit: 5.0,
                                count: 2499,
                            },
                            VectorHistogramBucket {
                                upper_limit: 10.0,
                                count: 5001,
                            },
                        ],
                        count: 11001,
                        sum: 60505.50000000138,
                    },
                    kind: "absolute",
                    name: "sample_histogram",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        Ok(())
    }

    #[test]
    fn test_metric_with_tags_to_json() -> Result<(), Error> {
        let gauge_vec = IntGaugeVec::new(
            Opts::new("sample_gauge", "sample_gauge help message"),
            &["label1", "label2"],
        )?;
        let registry = Registry::new();
        registry.register(Box::new(gauge_vec.clone()))?;

        gauge_vec.with_label_values(&["foo", "1"]).set(42);
        gauge_vec.with_label_values(&["bar", "2"]).set(98);

        assert_eq!(
            vec![
                VectorEvent {
                    metric: VectorMetric {
                        data: VectorMetricData::Gauge { value: 98.0 },
                        kind: "absolute",
                        name: "sample_gauge",
                        tags: [("label1", "bar"), ("label2", "2")]
                            .iter()
                            .copied()
                            .collect(),
                    }
                },
                VectorEvent {
                    metric: VectorMetric {
                        data: VectorMetricData::Gauge { value: 42.0 },
                        kind: "absolute",
                        name: "sample_gauge",
                        tags: [("label1", "foo"), ("label2", "1")]
                            .iter()
                            .copied()
                            .collect(),
                    }
                },
            ],
            families_to_json_events(&registry.gather())
        );

        Ok(())
    }

    #[test]
    fn test_encoding() -> Result<(), Error> {
        let gauge = IntGauge::with_opts(Opts::new("sample_gauge", "sample_gauge help message"))?;
        let registry = Registry::new();
        registry.register(Box::new(gauge.clone()))?;

        let mut output = Vec::new();
        LogEncoder::new().encode(&registry.gather(), &mut output)?;

        assert_eq!(
            b"crates-io-heroku-metrics:ingest W3sibWV0cmljIjp7ImdhdWdlIjp7InZhbHVlIjowLjB9LCJraW5kIjoiYWJzb2x1dGUiLCJuYW1lIjoic2FtcGxlX2dhdWdlIiwidGFncyI6e319fV0=\n",
            output.as_slice(),
        );

        Ok(())
    }
}
<commit_msg>split logged instance metrics into multiple lines when necessary<commit_after>use base64::write::EncoderWriter;
use indexmap::IndexMap;
use prometheus::proto::{MetricFamily, MetricType};
use prometheus::{Encoder, Error};
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer as _};
use serde_json::Serializer;
use std::cell::Cell;
use std::io::Write;
use std::rc::Rc;

const CHUNKS_MAX_SIZE_BYTES: usize = 5000;

/// The `LogEncoder` struct encodes Prometheus metrics in the format [`crates-io-heroku-metrics`]
/// expects metrics to be logged. This can be used to forward instance metrics to it, allowing them
/// to be scraped by the Rust infrastructure monitoring system.
///
/// The metrics are encoded in the format [Vector expects them][vector], and the list of metrics is
/// json-encoded and then base64-encoded. The whole thing is prefixed with a predefined string to
/// let [`crates-io-heroku-metrics`] find it easily.
///
/// This is needed mostly for crates.io hosted on Heroku. Deployments of crates.io on other
/// platforms shouldn't need this.
///
/// [`crates-io-heroku-metrics`]: https://github.com/rust-lang/crates-io-heroku-metrics
/// [vector]: https://vector.dev/docs/about/under-the-hood/architecture/data-model/metric/
#[derive(Debug, Clone, Copy)]
pub struct LogEncoder(());

impl LogEncoder {
    pub fn new() -> Self {
        Self(())
    }
}

impl Encoder for LogEncoder {
    fn encode<W: Write>(&self, families: &[MetricFamily], dest: &mut W) -> prometheus::Result<()> {
        let events = families_to_json_events(families);

        let chunks = serialize_and_split_list(events.iter(), CHUNKS_MAX_SIZE_BYTES)
            .map_err(|e| Error::Msg(e.to_string()))?;

        for chunk in chunks {
            dest.write_all(b"crates-io-heroku-metrics:ingest ")?;
            dest.write_all(&chunk)?;
            dest.write_all(b"\n")?;
        }

        Ok(())
    }

    fn format_type(&self) -> &str {
        "crates-io-heroku-metrics log encoding"
    }
}

fn families_to_json_events(families: &[MetricFamily]) -> Vec<VectorEvent<'_>> {
    let mut events = Vec::new();
    for family in families {
        for metric in family.get_metric() {
            let data = match family.get_field_type() {
                MetricType::COUNTER => VectorMetricData::Counter {
                    value: metric.get_counter().get_value(),
                },
                MetricType::GAUGE => VectorMetricData::Gauge {
                    value: metric.get_gauge().get_value(),
                },
                MetricType::HISTOGRAM => {
                    let histogram = metric.get_histogram();

                    // We need to convert from cumulative counts (used by the Prometheus library)
                    // to plain counts (used by Vector).
                    let mut buckets = Vec::new();
                    let mut last_cumulative_count = 0;
                    for bucket in histogram.get_bucket() {
                        buckets.push(VectorHistogramBucket {
                            upper_limit: bucket.get_upper_bound(),
                            count: bucket.get_cumulative_count() - last_cumulative_count,
                        });
                        last_cumulative_count = bucket.get_cumulative_count();
                    }

                    VectorMetricData::AggregatedHistogram {
                        count: histogram.get_sample_count(),
                        sum: histogram.get_sample_sum(),
                        buckets,
                    }
                }
                other => {
                    panic!("unsupported metric type: {:?}", other)
                }
            };
            events.push(VectorEvent {
                metric: VectorMetric {
                    data,
                    kind: "absolute",
                    name: family.get_name(),
                    tags: metric
                        .get_label()
                        .iter()
                        .map(|p| (p.get_name(), p.get_value()))
                        .collect(),
                },
            });
        }
    }
    events
}

/// Serialize a list of items into multiple Base64-encoded JSON chunks.
///
/// Our hosting platform (Heroku) limits the size of log lines, arbitrarily splitting them once
/// they reach a threshold. We can't let Heroku do the split as it doesn't know where to properly
/// do that, so we need to do the splitting ourselves.
///
/// This function takes an iterator of serializable items and returns the serialized version,
/// possibly split into multiple chunks. Each chunk is *at least* `max_size_hint` long, as the
/// function stops serializing new items in the same chunk only when the size limit is reached
/// after serializing an item.
///
/// Because of that `max_size_hint` should be lower than the upper bound we can't cross.
fn serialize_and_split_list<'a, S: Serialize + 'a>(
    items: impl Iterator<Item = &'a S>,
    max_size_hint: usize,
) -> Result<Vec<Vec<u8>>, serde_json::Error> {
    let mut items = items.peekable();

    let mut result = Vec::new();
    while items.peek().is_some() {
        let mut writer = TrackedWriter::new();
        let written_count = writer.written_count.clone();
        let mut serializer = Serializer::new(EncoderWriter::new(&mut writer, base64::STANDARD));

        let mut seq = serializer.serialize_seq(None)?;
        while let Some(next) = items.next() {
            seq.serialize_element(next)?;
            if written_count.get() >= max_size_hint {
                break;
            }
        }
        seq.end()?;
        drop(serializer);

        result.push(writer.buffer);
    }

    Ok(result)
}

struct TrackedWriter {
    buffer: Vec<u8>,
    written_count: Rc<Cell<usize>>,
}

impl TrackedWriter {
    fn new() -> Self {
        Self {
            buffer: Vec::new(),
            written_count: Rc::new(Cell::new(0)),
        }
    }
}

impl Write for TrackedWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        let written = self.buffer.write(buf)?;
        self.written_count.set(self.written_count.get() + written);
        Ok(written)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.buffer.flush()
    }
}

#[derive(Serialize, Debug, PartialEq)]
struct VectorEvent<'a> {
    metric: VectorMetric<'a>,
}

#[derive(Serialize, Debug, PartialEq)]
struct VectorMetric<'a> {
    #[serde(flatten)]
    data: VectorMetricData,
    kind: &'a str,
    name: &'a str,
    tags: IndexMap<&'a str, &'a str>,
}

#[derive(Serialize, Debug, PartialEq)]
#[serde(rename_all = "snake_case")]
enum VectorMetricData {
    AggregatedHistogram {
        buckets: Vec<VectorHistogramBucket>,
        count: u64,
        sum: f64,
    },
    Counter {
        value: f64,
    },
    Gauge {
        value: f64,
    },
}

#[derive(Serialize, Debug, PartialEq)]
struct VectorHistogramBucket {
    upper_limit: f64,
    count: u64,
}

#[cfg(test)]
mod tests {
    use super::*;
    use anyhow::Error;
    use prometheus::{Histogram, HistogramOpts, IntCounter, IntGauge, IntGaugeVec, Opts, Registry};

    #[test]
    fn test_counter_to_json() -> Result<(), Error> {
        let counter =
            IntCounter::with_opts(Opts::new("sample_counter", "sample_counter help message"))?;
        let registry = Registry::new();
        registry.register(Box::new(counter.clone()))?;

        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::Counter { value: 0.0 },
                    kind: "absolute",
                    name: "sample_counter",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        counter.inc_by(42);
        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::Counter { value: 42.0 },
                    kind: "absolute",
                    name: "sample_counter",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        Ok(())
    }

    #[test]
    fn test_gauge_to_json() -> Result<(), Error> {
        let gauge = IntGauge::with_opts(Opts::new("sample_gauge", "sample_gauge help message"))?;
        let registry = Registry::new();
        registry.register(Box::new(gauge.clone()))?;

        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::Gauge { value: 0.0 },
                    kind: "absolute",
                    name: "sample_gauge",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        gauge.set(42);
        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::Gauge { value: 42.0 },
                    kind: "absolute",
                    name: "sample_gauge",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        Ok(())
    }

    #[test]
    fn test_histogram_to_json() -> Result<(), Error> {
        let histogram = Histogram::with_opts(HistogramOpts::new(
            "sample_histogram",
            "sample_histogram help message",
        ))?;
        let registry = Registry::new();
        registry.register(Box::new(histogram.clone()))?;

        let mut value = 0.0;
        while value < 11.0 {
            histogram.observe(value);
            value += 0.001;
        }

        assert_eq!(
            vec![VectorEvent {
                metric: VectorMetric {
                    data: VectorMetricData::AggregatedHistogram {
                        buckets: vec![
                            VectorHistogramBucket {
                                upper_limit: 0.005,
                                count: 6,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.01,
                                count: 4,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.025,
                                count: 15,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.05,
                                count: 25,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.1,
                                count: 50,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.25,
                                count: 150,
                            },
                            VectorHistogramBucket {
                                upper_limit: 0.5,
                                count: 250,
                            },
                            VectorHistogramBucket {
                                upper_limit: 1.0,
                                count: 500,
                            },
                            VectorHistogramBucket {
                                upper_limit: 2.5,
                                count: 1501,
                            },
                            VectorHistogramBucket {
                                upper_limit: 5.0,
                                count: 2499,
                            },
                            VectorHistogramBucket {
                                upper_limit: 10.0,
                                count: 5001,
                            },
                        ],
                        count: 11001,
                        sum: 60505.50000000138,
                    },
                    kind: "absolute",
                    name: "sample_histogram",
                    tags: IndexMap::new(),
                }
            }],
            families_to_json_events(&registry.gather())
        );

        Ok(())
    }

    #[test]
    fn test_metric_with_tags_to_json() -> Result<(), Error> {
        let gauge_vec = IntGaugeVec::new(
            Opts::new("sample_gauge", "sample_gauge help message"),
            &["label1", "label2"],
        )?;
        let registry = Registry::new();
        registry.register(Box::new(gauge_vec.clone()))?;

        gauge_vec.with_label_values(&["foo", "1"]).set(42);
        gauge_vec.with_label_values(&["bar", "2"]).set(98);

        assert_eq!(
            vec![
                VectorEvent {
                    metric: VectorMetric {
                        data: VectorMetricData::Gauge { value: 98.0 },
                        kind: "absolute",
                        name: "sample_gauge",
                        tags: [("label1", "bar"), ("label2", "2")]
                            .iter()
                            .copied()
                            .collect(),
                    }
                },
                VectorEvent {
                    metric: VectorMetric {
                        data: VectorMetricData::Gauge { value: 42.0 },
                        kind: "absolute",
                        name: "sample_gauge",
                        tags: [("label1", "foo"), ("label2", "1")]
                            .iter()
                            .copied()
                            .collect(),
                    }
                },
            ],
            families_to_json_events(&registry.gather())
        );

        Ok(())
    }

    #[test]
    fn test_encoding() -> Result<(), Error> {
        let gauge = IntGauge::with_opts(Opts::new("sample_gauge", "sample_gauge help message"))?;
        let registry = Registry::new();
        registry.register(Box::new(gauge.clone()))?;

        let mut output = Vec::new();
        LogEncoder::new().encode(&registry.gather(), &mut output)?;

        assert_eq!(
            b"crates-io-heroku-metrics:ingest W3sibWV0cmljIjp7ImdhdWdlIjp7InZhbHVlIjowLjB9LCJraW5kIjoiYWJzb2x1dGUiLCJuYW1lIjoic2FtcGxlX2dhdWdlIiwidGFncyI6e319fV0=\n",
            output.as_slice(),
        );

        Ok(())
    }

    #[test]
    fn test_serialize_and_split_list_small() -> Result<(), Error> {
        let small = (0..10).collect::<Vec<_>>();
        let chunks = serialize_and_split_list(small.iter(), 256)?;

        assert_eq!(chunks.len(), 1);
        assert!(chunks[0].len() <= 256);
        assert_eq!(
            serde_json::from_slice::<Vec<usize>>(&base64::decode(&chunks[0])?)?,
            small,
        );

        Ok(())
    }

    #[test]
    fn test_serialize_and_split_list_long() -> Result<(), Error> {
        let small = (0..100).collect::<Vec<_>>();
        let chunks = serialize_and_split_list(small.iter(), 256)?;

        assert_eq!(chunks.len(), 2);
        assert!(chunks[0].len() >= 256);
        assert!(chunks[1].len() <= 256);
        assert_eq!(
            serde_json::from_slice::<Vec<usize>>(&base64::decode(&chunks[0])?)?,
            (0..=67).collect::<Vec<_>>(),
        );
        assert_eq!(
            serde_json::from_slice::<Vec<usize>>(&base64::decode(&chunks[1])?)?,
            (68..100).collect::<Vec<_>>(),
        );

        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::error::Error;
use crate::signature::{self, PublicKey};
use std::path::Path;
use wabt::{wat2wasm, ErrorKind};

pub fn read_module(
    path: impl AsRef<Path>,
    pk: &Option<PublicKey>,
    verify: bool,
) -> Result<Vec<u8>, Error> {
    let contents = std::fs::read(&path)?;
    if verify {
        let signature_box = signature::signature_box_for_module_path(&path)?;
        signature::verify_source_code(
            &contents,
            &signature_box,
            pk.as_ref()
                .ok_or(Error::Signature("public key is missing".to_string()))?,
        )?;
    }
    read_bytes(contents)
}

pub fn read_bytes(bytes: Vec<u8>) -> Result<Vec<u8>, Error> {
    if wasm_preamble(&bytes) {
        Ok(bytes)
    } else {
        wat2wasm(bytes).map_err(|err| {
            let mut result = format!("wat2wasm error: {}", err);
            match unsafe { std::mem::transmute::<wabt::Error, wabt::ErrorKind>(err) } {
                ErrorKind::Parse(msg) |
                // this shouldn't be reachable - we're going the other way
                ErrorKind::Deserialize(msg) |
                // not sure how this error comes up
                ErrorKind::ResolveNames(msg) |
                ErrorKind::Validate(msg) => {
                    result.push_str(":\n");
                    result.push_str(&msg);
                },
                _ => { }
            };
            crate::error::Error::Input(result)
        })
    }
}

pub fn wasm_preamble(buf: &[u8]) -> bool {
    if buf.len() > 4 {
        buf[0..4] == [0, 97, 115, 109]
    } else {
        false
    }
}
<commit_msg>Remove a no-longer-necessary transmute (#549)<commit_after>use crate::error::Error;
use crate::signature::{self, PublicKey};
use std::path::Path;
use wabt::{wat2wasm, ErrorKind};

pub fn read_module(
    path: impl AsRef<Path>,
    pk: &Option<PublicKey>,
    verify: bool,
) -> Result<Vec<u8>, Error> {
    let contents = std::fs::read(&path)?;
    if verify {
        let signature_box = signature::signature_box_for_module_path(&path)?;
        signature::verify_source_code(
            &contents,
            &signature_box,
            pk.as_ref()
                .ok_or(Error::Signature("public key is missing".to_string()))?,
        )?;
    }
    read_bytes(contents)
}

pub fn read_bytes(bytes: Vec<u8>) -> Result<Vec<u8>, Error> {
    if wasm_preamble(&bytes) {
        Ok(bytes)
    } else {
        wat2wasm(bytes).map_err(|err| {
            let mut result = format!("wat2wasm error: {}", err);
            match err.kind() {
                ErrorKind::Parse(msg) |
                // this shouldn't be reachable - we're going the other way
                ErrorKind::Deserialize(msg) |
                // not sure how this error comes up
                ErrorKind::ResolveNames(msg) |
                ErrorKind::Validate(msg) => {
                    result.push_str(":\n");
                    result.push_str(&msg);
                },
                _ => { }
            };
            crate::error::Error::Input(result)
        })
    }
}

pub fn wasm_preamble(buf: &[u8]) -> bool {
    if buf.len() > 4 {
        buf[0..4] == [0, 97, 115, 109]
    } else {
        false
    }
}
<|endoftext|>


<commit_before>#![crate_name = "sam4l"]
#![crate_type = "rlib"]
#![feature(asm,core_intrinsics,concat_idents,const_fn)]
#![no_std]

extern crate common;
extern crate hil;
extern crate process;

mod helpers;

pub mod chip;
pub mod ast;
pub mod dma;
pub mod i2c;
pub mod spi;
pub mod nvic;
pub mod pm;
pub mod gpio;
pub mod usart;
pub mod scif;
pub mod adc;

unsafe extern "C" fn unhandled_interrupt() {
    panic!("Unhandled Interrupt");
}

extern {
    // _estack is not really a function, but it makes the types work
    // You should never actually invoke it!!
    fn _estack();

    // Defined in src/main/main.rs
    fn main();

    // Defined in src/arch/cortex-m4/ctx_switch.S
    fn SVC_Handler();

    static mut _szero : u32;
    static mut _ezero : u32;
    static mut _etext : u32;
    static mut _srelocate : u32;
    static mut _erelocate : u32;
}

#[link_section=".vectors"]
pub static ISR_VECTOR: [Option<unsafe extern fn()>; 96] = [
    // First 16 are defined in the Cortex M4 user guide section 2.3.4

    /* Stack top */     Option::Some(_estack),
    /* Reset */         Option::Some(reset_handler),
    /* NMI */           Option::Some(unhandled_interrupt),
    /* Hard Fault */    Option::Some(hard_fault_handler),
    /* MemManage */     Option::Some(unhandled_interrupt),
    /* BusFault */      Option::Some(unhandled_interrupt),
    /* UsageFault*/     Option::Some(unhandled_interrupt),
    None, None, None, None,
    /* SVC */           Option::Some(SVC_Handler),
    /* DebugMon */      Option::Some(unhandled_interrupt),
    None,
    /* PendSV */        Option::Some(unhandled_interrupt),
    /* SysTick */       Option::Some(unhandled_interrupt),

    // Perhipheral vectors are defined by Atmel in the SAM4L datasheet section
    // 4.7.
    /* HFLASHC */       Option::Some(unhandled_interrupt),
    /* PDCA0 */         Option::Some(dma::PDCA_0_Handler),
    /* PDCA1 */         Option::Some(dma::PDCA_1_Handler),
    /* PDCA2 */         Option::Some(dma::PDCA_2_Handler),
    /* PDCA3..PDCA15 */ None, None, None, None, None, None, None, None, None,
                        None, None, None, None,
    /* CRCCU */         Option::Some(unhandled_interrupt),
    /* USBC */          Option::Some(unhandled_interrupt),
    /* PEVC_TR */       Option::Some(unhandled_interrupt),
    /* PEVC_OV */       Option::Some(unhandled_interrupt),
    /* AESA */          Option::Some(unhandled_interrupt),
    /* PM */            Option::Some(unhandled_interrupt),
    /* SCIF */          Option::Some(unhandled_interrupt),
    /* FREQM */         Option::Some(unhandled_interrupt),
    /* GPIO0 */         Option::Some(gpio::GPIO_0_Handler),
    /* GPIO1 */         Option::Some(gpio::GPIO_1_Handler),
    /* GPIO2 */         Option::Some(gpio::GPIO_2_Handler),
    /* GPIO3 */         Option::Some(gpio::GPIO_3_Handler),
    /* GPIO4 */         Option::Some(gpio::GPIO_4_Handler),
    /* GPIO5 */         Option::Some(gpio::GPIO_5_Handler),
    /* GPIO6 */         Option::Some(gpio::GPIO_6_Handler),
    /* GPIO7 */         Option::Some(gpio::GPIO_7_Handler),
    /* GPIO8 */         Option::Some(gpio::GPIO_8_Handler),
    /* GPIO9 */         Option::Some(gpio::GPIO_9_Handler),
    /* GPIO10 */        Option::Some(gpio::GPIO_10_Handler),
    /* GPIO11 */        Option::Some(gpio::GPIO_11_Handler),
    /* BPM */           Option::Some(unhandled_interrupt),
    /* BSCIF */         Option::Some(unhandled_interrupt),
    /* AST_ALARM */     Option::Some(ast::AST_ALARM_Handler),
    /* AST_PER */       Option::Some(unhandled_interrupt),
    /* AST_OVF */       Option::Some(unhandled_interrupt),
    /* AST_READY */     Option::Some(unhandled_interrupt),
    /* AST_CLKREADY */  Option::Some(unhandled_interrupt),
    /* WDT */           Option::Some(unhandled_interrupt),
    /* EIC1 */          Option::Some(unhandled_interrupt),
    /* EIC2 */          Option::Some(unhandled_interrupt),
    /* EIC3 */          Option::Some(unhandled_interrupt),
    /* EIC4 */          Option::Some(unhandled_interrupt),
    /* EIC5 */          Option::Some(unhandled_interrupt),
    /* EIC6 */          Option::Some(unhandled_interrupt),
    /* EIC7 */          Option::Some(unhandled_interrupt),
    /* EIC8 */          Option::Some(unhandled_interrupt),
    /* IISC */          Option::Some(unhandled_interrupt),
    /* SPI */           Option::Some(unhandled_interrupt),
    /* TC00 */          Option::Some(unhandled_interrupt),
    /* TC01 */          Option::Some(unhandled_interrupt),
    /* TC02 */          Option::Some(unhandled_interrupt),
    /* TC10 */          Option::Some(unhandled_interrupt),
    /* TC11 */          Option::Some(unhandled_interrupt),
    /* TC12 */          Option::Some(unhandled_interrupt),
    /* TWIM0 */         Option::Some(unhandled_interrupt),
    /* TWIS0 */         Option::Some(unhandled_interrupt),
    /* TWIM1 */         Option::Some(unhandled_interrupt),
    /* TWIS1 */         Option::Some(unhandled_interrupt),
    /* USART0 */        Option::Some(unhandled_interrupt),
    /* USART1 */        Option::Some(unhandled_interrupt),
    /* USART2 */        Option::Some(unhandled_interrupt),
    /* USART3 */        Option::Some(usart::USART3_Handler),
    /* ADCIFE */        Option::Some(adc::ADCIFE_Handler),
    /* DACC */          Option::Some(unhandled_interrupt),
    /* ACIFC */         Option::Some(unhandled_interrupt),
    /* ABDACB */        Option::Some(unhandled_interrupt),
    /* TRNG */          Option::Some(unhandled_interrupt),
    /* PARC */          Option::Some(unhandled_interrupt),
    /* CATB */          Option::Some(unhandled_interrupt),
    None,
    /* TWIM2 */         Option::Some(unhandled_interrupt),
    /* TWIM3 */         Option::Some(unhandled_interrupt),
    /* LCDCA */         Option::Some(unhandled_interrupt),
];

unsafe extern "C" fn reset_handler() {

    // Relocate data segment.
    // Assumes data starts right after text segment as specified by the linker
    // file.
    let mut pdest  = &mut _srelocate as *mut u32;
    let pend  = &mut _erelocate as *mut u32;
    let mut psrc = &_etext as *const u32;

    if psrc != pdest {
        while (pdest as *const u32) < pend {
            *pdest = *psrc;
            pdest = pdest.offset(1);
            psrc = psrc.offset(1);
        }
    }

    // Clear the zero segment (BSS)
    let pzero = &_ezero as *const u32;
    pdest = &mut _szero as *mut u32;

    while (pdest as *const u32) < pzero {
        *pdest = 0;
        pdest = pdest.offset(1);
    }

    main();
}

unsafe extern "C" fn hard_fault_handler() {
    let faulting_stack: *const u32;

    asm!(
        "tst    lr, #4                      \n\
         ite    eq                          \n\
         mrseq  r0, msp                     \n\
         mrsne  r0, psp                     \n\
         movs   r1, #0                      "
        : "={r1}"(faulting_stack)
        :
        : "r1"
        :
        );

    let stacked_r0  = *faulting_stack;
    let stacked_r1  = *faulting_stack+4;
    let stacked_r2  = *faulting_stack+8;
    let stacked_r3  = *faulting_stack+12;
    let stacked_r12 = *faulting_stack+16;
    let stacked_lr  = *faulting_stack+20;
    let stacked_pc  = *faulting_stack+24;
    let stacked_prs = *faulting_stack+28;

    panic!("HardFault.\n\
           \tr0  0x{:x}\n\
           \tr1  0x{:x}\n\
           \tr2  0x{:x}\n\
           \tr3  0x{:x}\n\
           \tr12 0x{:x}\n\
           \tlr  0x{:x}\n\
           \tpc  0x{:x}\n\
           \tprs 0x{:x}\n\
           ", stacked_r0, stacked_r1, stacked_r2, stacked_r3,
           stacked_r12, stacked_lr, stacked_pc, stacked_prs);
}

<commit_msg>Compute offsets correctly when reading faulted stack<commit_after>#![crate_name = "sam4l"]
#![crate_type = "rlib"]
#![feature(asm,core_intrinsics,concat_idents,const_fn)]
#![no_std]

extern crate common;
extern crate hil;
extern crate process;

mod helpers;

pub mod chip;
pub mod ast;
pub mod dma;
pub mod i2c;
pub mod spi;
pub mod nvic;
pub mod pm;
pub mod gpio;
pub mod usart;
pub mod scif;
pub mod adc;

unsafe extern "C" fn unhandled_interrupt() {
    panic!("Unhandled Interrupt");
}

extern {
    // _estack is not really a function, but it makes the types work
    // You should never actually invoke it!!
    fn _estack();

    // Defined in src/main/main.rs
    fn main();

    // Defined in src/arch/cortex-m4/ctx_switch.S
    fn SVC_Handler();

    static mut _szero : u32;
    static mut _ezero : u32;
    static mut _etext : u32;
    static mut _srelocate : u32;
    static mut _erelocate : u32;
}

#[link_section=".vectors"]
pub static ISR_VECTOR: [Option<unsafe extern fn()>; 96] = [
    // First 16 are defined in the Cortex M4 user guide section 2.3.4

    /* Stack top */     Option::Some(_estack),
    /* Reset */         Option::Some(reset_handler),
    /* NMI */           Option::Some(unhandled_interrupt),
    /* Hard Fault */    Option::Some(hard_fault_handler),
    /* MemManage */     Option::Some(unhandled_interrupt),
    /* BusFault */      Option::Some(unhandled_interrupt),
    /* UsageFault*/     Option::Some(unhandled_interrupt),
    None, None, None, None,
    /* SVC */           Option::Some(SVC_Handler),
    /* DebugMon */      Option::Some(unhandled_interrupt),
    None,
    /* PendSV */        Option::Some(unhandled_interrupt),
    /* SysTick */       Option::Some(unhandled_interrupt),

    // Perhipheral vectors are defined by Atmel in the SAM4L datasheet section
    // 4.7.
    /* HFLASHC */       Option::Some(unhandled_interrupt),
    /* PDCA0 */         Option::Some(dma::PDCA_0_Handler),
    /* PDCA1 */         Option::Some(dma::PDCA_1_Handler),
    /* PDCA2 */         Option::Some(dma::PDCA_2_Handler),
    /* PDCA3..PDCA15 */ None, None, None, None, None, None, None, None, None,
                        None, None, None, None,
    /* CRCCU */         Option::Some(unhandled_interrupt),
    /* USBC */          Option::Some(unhandled_interrupt),
    /* PEVC_TR */       Option::Some(unhandled_interrupt),
    /* PEVC_OV */       Option::Some(unhandled_interrupt),
    /* AESA */          Option::Some(unhandled_interrupt),
    /* PM */            Option::Some(unhandled_interrupt),
    /* SCIF */          Option::Some(unhandled_interrupt),
    /* FREQM */         Option::Some(unhandled_interrupt),
    /* GPIO0 */         Option::Some(gpio::GPIO_0_Handler),
    /* GPIO1 */         Option::Some(gpio::GPIO_1_Handler),
    /* GPIO2 */         Option::Some(gpio::GPIO_2_Handler),
    /* GPIO3 */         Option::Some(gpio::GPIO_3_Handler),
    /* GPIO4 */         Option::Some(gpio::GPIO_4_Handler),
    /* GPIO5 */         Option::Some(gpio::GPIO_5_Handler),
    /* GPIO6 */         Option::Some(gpio::GPIO_6_Handler),
    /* GPIO7 */         Option::Some(gpio::GPIO_7_Handler),
    /* GPIO8 */         Option::Some(gpio::GPIO_8_Handler),
    /* GPIO9 */         Option::Some(gpio::GPIO_9_Handler),
    /* GPIO10 */        Option::Some(gpio::GPIO_10_Handler),
    /* GPIO11 */        Option::Some(gpio::GPIO_11_Handler),
    /* BPM */           Option::Some(unhandled_interrupt),
    /* BSCIF */         Option::Some(unhandled_interrupt),
    /* AST_ALARM */     Option::Some(ast::AST_ALARM_Handler),
    /* AST_PER */       Option::Some(unhandled_interrupt),
    /* AST_OVF */       Option::Some(unhandled_interrupt),
    /* AST_READY */     Option::Some(unhandled_interrupt),
    /* AST_CLKREADY */  Option::Some(unhandled_interrupt),
    /* WDT */           Option::Some(unhandled_interrupt),
    /* EIC1 */          Option::Some(unhandled_interrupt),
    /* EIC2 */          Option::Some(unhandled_interrupt),
    /* EIC3 */          Option::Some(unhandled_interrupt),
    /* EIC4 */          Option::Some(unhandled_interrupt),
    /* EIC5 */          Option::Some(unhandled_interrupt),
    /* EIC6 */          Option::Some(unhandled_interrupt),
    /* EIC7 */          Option::Some(unhandled_interrupt),
    /* EIC8 */          Option::Some(unhandled_interrupt),
    /* IISC */          Option::Some(unhandled_interrupt),
    /* SPI */           Option::Some(unhandled_interrupt),
    /* TC00 */          Option::Some(unhandled_interrupt),
    /* TC01 */          Option::Some(unhandled_interrupt),
    /* TC02 */          Option::Some(unhandled_interrupt),
    /* TC10 */          Option::Some(unhandled_interrupt),
    /* TC11 */          Option::Some(unhandled_interrupt),
    /* TC12 */          Option::Some(unhandled_interrupt),
    /* TWIM0 */         Option::Some(unhandled_interrupt),
    /* TWIS0 */         Option::Some(unhandled_interrupt),
    /* TWIM1 */         Option::Some(unhandled_interrupt),
    /* TWIS1 */         Option::Some(unhandled_interrupt),
    /* USART0 */        Option::Some(unhandled_interrupt),
    /* USART1 */        Option::Some(unhandled_interrupt),
    /* USART2 */        Option::Some(unhandled_interrupt),
    /* USART3 */        Option::Some(usart::USART3_Handler),
    /* ADCIFE */        Option::Some(adc::ADCIFE_Handler),
    /* DACC */          Option::Some(unhandled_interrupt),
    /* ACIFC */         Option::Some(unhandled_interrupt),
    /* ABDACB */        Option::Some(unhandled_interrupt),
    /* TRNG */          Option::Some(unhandled_interrupt),
    /* PARC */          Option::Some(unhandled_interrupt),
    /* CATB */          Option::Some(unhandled_interrupt),
    None,
    /* TWIM2 */         Option::Some(unhandled_interrupt),
    /* TWIM3 */         Option::Some(unhandled_interrupt),
    /* LCDCA */         Option::Some(unhandled_interrupt),
];

unsafe extern "C" fn reset_handler() {

    // Relocate data segment.
    // Assumes data starts right after text segment as specified by the linker
    // file.
    let mut pdest  = &mut _srelocate as *mut u32;
    let pend  = &mut _erelocate as *mut u32;
    let mut psrc = &_etext as *const u32;

    if psrc != pdest {
        while (pdest as *const u32) < pend {
            *pdest = *psrc;
            pdest = pdest.offset(1);
            psrc = psrc.offset(1);
        }
    }

    // Clear the zero segment (BSS)
    let pzero = &_ezero as *const u32;
    pdest = &mut _szero as *mut u32;

    while (pdest as *const u32) < pzero {
        *pdest = 0;
        pdest = pdest.offset(1);
    }

    main();
}

unsafe extern "C" fn hard_fault_handler() {
    use core::intrinsics::offset;

    let faulting_stack: *mut u32;

    asm!(
        "tst    lr, #4                      \n\
         ite    eq                          \n\
         mrseq  r0, msp                     \n\
         mrsne  r0, psp                     "
        : "={r0}"(faulting_stack)
        :
        : "r0"
        :
        );

    let stacked_r0  :u32 = *offset(faulting_stack, 0);
    let stacked_r1  :u32 = *offset(faulting_stack, 1);
    let stacked_r2  :u32 = *offset(faulting_stack, 2);
    let stacked_r3  :u32 = *offset(faulting_stack, 3);
    let stacked_r12 :u32 = *offset(faulting_stack, 4);
    let stacked_lr  :u32 = *offset(faulting_stack, 5);
    let stacked_pc  :u32 = *offset(faulting_stack, 6);
    let stacked_prs :u32 = *offset(faulting_stack, 7);

    panic!("HardFault.\n\
           \tr0  0x{:x}\n\
           \tr1  0x{:x}\n\
           \tr2  0x{:x}\n\
           \tr3  0x{:x}\n\
           \tr12 0x{:x}\n\
           \tlr  0x{:x}\n\
           \tpc  0x{:x}\n\
           \tprs 0x{:x}\n\
           ", stacked_r0, stacked_r1, stacked_r2, stacked_r3,
           stacked_r12, stacked_lr, stacked_pc, stacked_prs);
}

<|endoftext|>


<commit_before>// crypto_core_salsa20.h

pub const crypto_core_salsa20_OUTPUTBYTES: usize = 64;
pub const crypto_core_salsa20_INPUTBYTES: usize = 16;
pub const crypto_core_salsa20_KEYBYTES: usize = 32;
pub const crypto_core_salsa20_CONSTBYTES: usize = 16;

extern {
    pub fn crypto_core_salsa20_outputbytes() -> size_t;
    pub fn crypto_core_salsa20_inputbytes() -> size_t;
    pub fn crypto_core_salsa20_keybytes() -> size_t;
    pub fn crypto_core_salsa20_constbytes() -> size_t;

    pub fn crypto_core_salsa20(
        out: *mut [u8; crypto_core_salsa20_OUTPUTBYTES],
        in_: *const [u8; crypto_core_salsa20_INPUTBYTES],
        k: *const [u8; crypto_core_salsa20_KEYBYTES],
        c: *const [u8; crypto_core_salsa20_CONSTBYTES]) -> c_int;
}

#[test]
fn test_crypto_core_salsa20_outputbytes() {
    assert!(unsafe {
        crypto_core_salsa20_outputbytes() as usize
    } == crypto_core_salsa20_OUTPUTBYTES)
}
#[test]
fn test_crypto_core_salsa20_inputbytes() {
    assert!(unsafe {
        crypto_core_salsa20_inputbytes() as usize
    } == crypto_core_salsa20_INPUTBYTES)
}
#[test]
fn test_crypto_core_salsa20_keybytes() {
    assert!(unsafe {
        crypto_core_salsa20_keybytes() as usize
    } == crypto_core_salsa20_KEYBYTES)
}
#[test]
fn test_crypto_core_salsa20_constbytes() {
    assert!(unsafe {
        crypto_core_salsa20_constbytes() as usize
    } == crypto_core_salsa20_CONSTBYTES)
}
<commit_msg>whitespace changes<commit_after>// crypto_core_salsa20.h

pub const crypto_core_salsa20_OUTPUTBYTES: usize = 64;
pub const crypto_core_salsa20_INPUTBYTES: usize = 16;
pub const crypto_core_salsa20_KEYBYTES: usize = 32;
pub const crypto_core_salsa20_CONSTBYTES: usize = 16;

extern {
    pub fn crypto_core_salsa20_outputbytes() -> size_t;
    pub fn crypto_core_salsa20_inputbytes() -> size_t;
    pub fn crypto_core_salsa20_keybytes() -> size_t;
    pub fn crypto_core_salsa20_constbytes() -> size_t;

    pub fn crypto_core_salsa20(
        out: *mut [u8; crypto_core_salsa20_OUTPUTBYTES],
        in_: *const [u8; crypto_core_salsa20_INPUTBYTES],
        k: *const [u8; crypto_core_salsa20_KEYBYTES],
        c: *const [u8; crypto_core_salsa20_CONSTBYTES]) -> c_int;
}

#[test]
fn test_crypto_core_salsa20_outputbytes() {
    assert!(unsafe {
        crypto_core_salsa20_outputbytes() as usize
    } == crypto_core_salsa20_OUTPUTBYTES)
}

#[test]
fn test_crypto_core_salsa20_inputbytes() {
    assert!(unsafe {
        crypto_core_salsa20_inputbytes() as usize
    } == crypto_core_salsa20_INPUTBYTES)
}

#[test]
fn test_crypto_core_salsa20_keybytes() {
    assert!(unsafe {
        crypto_core_salsa20_keybytes() as usize
    } == crypto_core_salsa20_KEYBYTES)
}

#[test]
fn test_crypto_core_salsa20_constbytes() {
    assert!(unsafe {
        crypto_core_salsa20_constbytes() as usize
    } == crypto_core_salsa20_CONSTBYTES)
}
<|endoftext|>


<commit_before>//! MemTable is a in-memory table representation.
//!
//! MemTable is designed to be used to contain the result or for fastest processing.

use rustc_serialize::{Decoder, Decodable};

use session::Session;
use err;
use err::{Void, void_ok};
use page::{c_api, Page};
use types::Ty;

use util::collection::vec;

pub struct MemTable
{
	types   : Vec<Ty>,
	fields  : Vec<String>,

	pages   : Vec<Page>,
	row_num : usize
}

impl MemTable
{
	pub fn new(session: &Session, types: &[&Ty], fields: &[&str]) -> MemTable
	{
		debug_assert!(types.len() == fields.len());

		MemTable {
			types   : types.iter().map(|e| (*e).clone()).collect::<Vec<Ty>>(),
			fields  : fields.iter().map(|f| f.to_string()).collect::<Vec<String>>(),
			pages   : Vec::new(),
			row_num : 0
		}
	}
}

impl MemTable
{
	pub fn row_num(&self) -> usize
	{
		self.row_num
	}

	pub fn col_num(&self) -> usize
	{
		self.types.len()
	}

	pub fn types(&self) -> &Vec<Ty>
	{
		&self.types
	}

	pub fn fields(&self) -> &Vec<String>
	{
		&self.fields
	}

	pub fn reader<'a, D: Decodable>(&'a self) -> DecodedRecords<'a, D>
	{
		DecodedRecords {
			pages_it: self.pages.iter(),
			cur_page: None,
			types   : &self.types,
			row_pos : 0,
			col_pos : 0,
			marker  : ::std::marker::PhantomData
		}
	}

	pub fn write(&mut self, page: &Page) -> Void
	{
		self.row_num += page.value_count() as usize;
		self.pages.push(page.copy());

		void_ok
	}

	pub fn close(&mut self) -> Void
	{
		self.pages.clear();

		void_ok
	}
}

use std::slice::Iter;

pub struct DecodedRecords<'a, D>
{
	pages_it: Iter<'a, Page>,
	cur_page: Option<&'a Page>,
	types   : &'a Vec<Ty>,
	row_pos : usize,
	col_pos : usize,
	marker: ::std::marker::PhantomData<D>,
}

impl<'a, D> DecodedRecords<'a, D>
{
	fn next_page(&mut self) {
		println!(">>> DecodedRecords::next_page() invoked.");
		loop {
  		self.cur_page = self.pages_it.next();

  		if self.cur_page.is_none() {
  			break;
  		}

  		if self.cur_page.unwrap().value_count() == 0 {
 				continue;
			} else {
				break;
			}
		}
		self.row_pos  = 0;
	}

	#[inline(always)]
	fn validate(&self) {
		debug_assert!(self.row_pos  < self.cur_page.unwrap().value_count());
   	debug_assert!(self.col_pos  < self.types.len());
	}
}

impl<'a, D> Iterator for DecodedRecords<'a, D> where D: Decodable {
  type Item = DecodingResult<D>;

  fn next(&mut self) -> Option<DecodingResult<D>> {
  	println!(">>> row pos: {}", self.row_pos);

  	match self.cur_page {
  		Some(p) if self.row_pos >= p.value_count()  => self.next_page(),
  		None => self.next_page(),
  		_    => {}
  	};

  	if let Some(p) = self.cur_page {
  	  let r = Decodable::decode(self);
  	  self.row_pos += 1;

  	  Some(r)
 		} else {
 			None
 		}
  }
}

pub enum MemTableDecoderError
{
	TypeMismatch
}

pub type DecodingResult<T> = Result<T, MemTableDecoderError>;

impl<'a, D> Decoder for DecodedRecords<'a, D> {
    type Error = MemTableDecoderError;

    // Primitive types:
    fn read_nil(&mut self) -> Result<(), Self::Error>
    {
    	Ok(())
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error>
    {
    	unimplemented!();
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error>
    {
    	unimplemented!();
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error>
    {
    	unimplemented!();
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error>
    {
    	unimplemented!();
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error>
    {
    	unimplemented!();
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error>
    {
    	unimplemented!();
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error>
    {
			self.validate();

    	let row_pos  = self.row_pos;
    	let col_pos  = self.col_pos;

    	let chunk = self.cur_page.unwrap().chunk(col_pos);
    	Ok(unsafe{c_api::read_i64_raw(chunk, row_pos)})
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error>
    {
    	self.validate();

    	let row_pos  = self.row_pos;
    	let col_pos  = self.col_pos;

    	let chunk = self.cur_page.unwrap().chunk(col_pos);
    	Ok(unsafe{c_api::read_i32_raw(chunk, row_pos)})
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error>
    {
//    	debug_assert!(self.page_pos < self.pages.len());
//    	debug_assert!(self.row_pos  < self.pages[self.page_pos].value_count());
//    	debug_assert!(self.col_pos  < self.types.len());
//
//    	let page_pos = self.page_pos;
//    	let row_pos  = self.row_pos;
//    	let col_pos  = self.col_pos;
//
//    	let mini_page = self.pages[page_pos].minipage(col_pos);
//    	Ok(mini_page.read_i16(row_pos))
			unimplemented!();
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error>
    {
//    	let page_pos = self.page_pos;
//    	let row_pos  = self.row_pos;
//    	let col_pos  = self.col_pos;
//
//    	let mini_page = self.pages[page_pos].minipage(col_pos);
//    	Ok(mini_page.read_i8(row_pos))
			unimplemented!();
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error>
    {
    	unimplemented!();
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error>
    {
			self.validate();

    	let row_pos  = self.row_pos;
    	let col_pos  = self.col_pos;

    	let chunk = self.cur_page.unwrap().chunk(col_pos);
    	Ok(unsafe {c_api::read_f64_raw(chunk, row_pos)})
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error>
    {
			self.validate();

    	let row_pos  = self.row_pos;
    	let col_pos  = self.col_pos;

    	let chunk = self.cur_page.unwrap().chunk(col_pos);
    	Ok(unsafe {c_api::read_f32_raw(chunk, row_pos)})
    }

    fn read_char(&mut self) -> Result<char, Self::Error>
    {
    	unimplemented!();
    }

    fn read_str(&mut self) -> Result<String, Self::Error>
    {
    	unimplemented!();
    }

    // Compound types:
    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F)
                               -> Result<T, Self::Error>
        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F)
                                   -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F)
                                      -> Result<T, Self::Error>
        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_enum_struct_variant_field<T, F>(&mut self,
                                            f_name: &str,
                                            f_idx: usize,
                                            f: F)
                                            -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F)
                         -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_struct_field<T, F>(&mut self,
                               f_name: &str,
                               f_idx: usize,
                               f: F)
                               -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	self.col_pos = 0;
      f(self)
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F)
                            -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	let r = f(self);
    	self.col_pos+=1;

    	r
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F)
                               -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
     	unimplemented!();
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F)
                                   -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    // Specialized types:
    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F)
                              -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F)
                              -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    // Failure
    fn error(&mut self, err: &str) -> Self::Error
    {
    	unimplemented!();
    }
}<commit_msg>Reindent some one line functions.<commit_after>//! MemTable is a in-memory table representation.
//!
//! MemTable is designed to be used to contain the result or for fastest processing.

use rustc_serialize::{Decoder, Decodable};

use session::Session;
use err;
use err::{Void, void_ok};
use page::{c_api, Page};
use types::Ty;

use util::collection::vec;

pub struct MemTable
{
	types   : Vec<Ty>,
	fields  : Vec<String>,

	pages   : Vec<Page>,
	row_num : usize
}

impl MemTable
{
	pub fn new(session: &Session, types: &[&Ty], fields: &[&str]) -> MemTable
	{
		debug_assert!(types.len() == fields.len());

		MemTable {
			types   : types.iter().map(|e| (*e).clone()).collect::<Vec<Ty>>(),
			fields  : fields.iter().map(|f| f.to_string()).collect::<Vec<String>>(),
			pages   : Vec::new(),
			row_num : 0
		}
	}
}

impl MemTable
{
	pub fn row_num(&self) -> usize { self.row_num }

	pub fn col_num(&self) -> usize { self.types.len() }

	pub fn types(&self) -> &Vec<Ty> {	&self.types }

	pub fn fields(&self) -> &Vec<String> { &self.fields }

	pub fn reader<'a, D: Decodable>(&'a self) -> DecodedRecords<'a, D>
	{
		DecodedRecords {
			pages_it: self.pages.iter(),
			cur_page: None,
			types   : &self.types,
			row_pos : 0,
			col_pos : 0,
			marker  : ::std::marker::PhantomData
		}
	}

	pub fn write(&mut self, page: &Page) -> Void
	{
		self.row_num += page.value_count() as usize;
		self.pages.push(page.copy());

		void_ok
	}

	pub fn close(&mut self) -> Void
	{
		self.pages.clear();
		void_ok
	}
}

use std::slice::Iter;

pub struct DecodedRecords<'a, D>
{
	pages_it: Iter<'a, Page>,
	cur_page: Option<&'a Page>,
	types   : &'a Vec<Ty>,
	row_pos : usize,
	col_pos : usize,
	marker: ::std::marker::PhantomData<D>,
}

impl<'a, D> DecodedRecords<'a, D>
{
	fn next_page(&mut self) {
		loop {
  		self.cur_page = self.pages_it.next();

  		if self.cur_page.is_none() {
  			break;
  		}

  		if self.cur_page.unwrap().value_count() == 0 {
 				continue;
			} else {
				break;
			}
		}
		self.row_pos  = 0;
	}

	#[inline(always)]
	fn validate(&self) {
		debug_assert!(self.row_pos  < self.cur_page.unwrap().value_count());
   	debug_assert!(self.col_pos  < self.types.len());
	}
}

impl<'a, D> Iterator for DecodedRecords<'a, D> where D: Decodable {
  type Item = DecodingResult<D>;

  fn next(&mut self) -> Option<DecodingResult<D>> {
  	println!(">>> row pos: {}", self.row_pos);

  	match self.cur_page {
  		Some(p) if self.row_pos >= p.value_count()  => self.next_page(),
  		None => self.next_page(),
  		_    => {}
  	};

  	if let Some(p) = self.cur_page {
  	  let r = Decodable::decode(self);
  	  self.row_pos += 1;

  	  Some(r)
 		} else {
 			None
 		}
  }
}

pub enum MemTableDecoderError
{
	TypeMismatch
}

pub type DecodingResult<T> = Result<T, MemTableDecoderError>;

impl<'a, D> Decoder for DecodedRecords<'a, D> {
    type Error = MemTableDecoderError;

    // Primitive types:
    fn read_nil(&mut self) -> Result<(), Self::Error>
    {
    	Ok(())
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error>
    {
    	unimplemented!();
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error>
    {
    	unimplemented!();
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error>
    {
    	unimplemented!();
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error>
    {
    	unimplemented!();
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error>
    {
    	unimplemented!();
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error>
    {
    	unimplemented!();
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error>
    {
			self.validate();

    	let row_pos  = self.row_pos;
    	let col_pos  = self.col_pos;

    	let chunk = self.cur_page.unwrap().chunk(col_pos);
    	Ok(unsafe{c_api::read_i64_raw(chunk, row_pos)})
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error>
    {
    	self.validate();

    	let row_pos  = self.row_pos;
    	let col_pos  = self.col_pos;

    	let chunk = self.cur_page.unwrap().chunk(col_pos);
    	Ok(unsafe{c_api::read_i32_raw(chunk, row_pos)})
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error>
    {
//    	debug_assert!(self.page_pos < self.pages.len());
//    	debug_assert!(self.row_pos  < self.pages[self.page_pos].value_count());
//    	debug_assert!(self.col_pos  < self.types.len());
//
//    	let page_pos = self.page_pos;
//    	let row_pos  = self.row_pos;
//    	let col_pos  = self.col_pos;
//
//    	let mini_page = self.pages[page_pos].minipage(col_pos);
//    	Ok(mini_page.read_i16(row_pos))
			unimplemented!();
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error>
    {
//    	let page_pos = self.page_pos;
//    	let row_pos  = self.row_pos;
//    	let col_pos  = self.col_pos;
//
//    	let mini_page = self.pages[page_pos].minipage(col_pos);
//    	Ok(mini_page.read_i8(row_pos))
			unimplemented!();
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error>
    {
    	unimplemented!();
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error>
    {
			self.validate();

    	let row_pos  = self.row_pos;
    	let col_pos  = self.col_pos;

    	let chunk = self.cur_page.unwrap().chunk(col_pos);
    	Ok(unsafe {c_api::read_f64_raw(chunk, row_pos)})
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error>
    {
			self.validate();

    	let row_pos  = self.row_pos;
    	let col_pos  = self.col_pos;

    	let chunk = self.cur_page.unwrap().chunk(col_pos);
    	Ok(unsafe {c_api::read_f32_raw(chunk, row_pos)})
    }

    fn read_char(&mut self) -> Result<char, Self::Error>
    {
    	unimplemented!();
    }

    fn read_str(&mut self) -> Result<String, Self::Error>
    {
    	unimplemented!();
    }

    // Compound types:
    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F)
                               -> Result<T, Self::Error>
        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F)
                                   -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F)
                                      -> Result<T, Self::Error>
        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_enum_struct_variant_field<T, F>(&mut self,
                                            f_name: &str,
                                            f_idx: usize,
                                            f: F)
                                            -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F)
                         -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_struct_field<T, F>(&mut self,
                               f_name: &str,
                               f_idx: usize,
                               f: F)
                               -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	self.col_pos = 0;
      f(self)
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F)
                            -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	let r = f(self);
    	self.col_pos+=1;

    	r
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F)
                               -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
     	unimplemented!();
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F)
                                   -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    // Specialized types:
    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
    	unimplemented!();
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F)
                              -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F)
                              -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
      unimplemented!();
    }

    // Failure
    fn error(&mut self, err: &str) -> Self::Error
    {
    	unimplemented!();
    }
}<|endoftext|>


<commit_before>import std::os;
import std::fs;
import std::os_fs;
import std::vec;
import std::map;
import std::str;
import std::uint;
import metadata::cstore;
import driver::session;
import util::filesearch;

// FIXME #721: Despite the compiler warning, test does exist and needs
// to be exported
export get_rpath_flags, test;

fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
    let os = sess.get_targ_cfg().os;

    // No rpath on windows
    if os == session::os_win32 {
        ret [];
    }

    log "preparing the RPATH!";

    let cwd = os::getcwd();
    let sysroot = sess.filesearch().sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.get_cstore());
    // We don't currently rpath native libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = libs + [get_sysroot_absolute_rt_lib(sess)];

    let target_triple = sess.get_opts().target_triple;
    let rpaths = get_rpaths(os, cwd, sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path {
    let path = [sess.filesearch().sysroot()]
        + filesearch::relative_target_lib_path(
            sess.get_opts().target_triple)
        + [os::dylib_filename("rustrt")];
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn rpaths_to_flags(rpaths: [str]) -> [str] {
    vec::map({ |rpath| #fmt("-Wl,-rpath,%s",rpath)}, rpaths)
}

fn get_rpaths(os: session::os, cwd: fs::path, sysroot: fs::path,
              output: fs::path, libs: [fs::path],
              target_triple: str) -> [str] {
    log #fmt("cwd: %s", cwd);
    log #fmt("sysroot: %s", sysroot);
    log #fmt("output: %s", output);
    log #fmt("libs:");
    for libpath in libs {
        log #fmt("    %s", libpath);
    }
    log #fmt("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, cwd, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(cwd, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = [get_install_prefix_rpath(cwd, target_triple)];

    fn log_rpaths(desc: str, rpaths: [str]) {
        log #fmt("%s rpaths:", desc);
        for rpath in rpaths {
            log #fmt("    %s", rpath);
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("absolute", abs_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths;

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    ret rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 cwd: fs::path,
                                 output: fs::path,
                                 libs: [fs::path]) -> [str] {
    vec::map(bind get_rpath_relative_to_output(os, cwd, output, _), libs)
}

fn get_rpath_relative_to_output(os: session::os,
                                cwd: fs::path,
                                output: fs::path,
                                lib: fs::path) -> str {
    // Mac doesn't appear to support $ORIGIN
    let prefix = alt os {
        session::os_linux. { "$ORIGIN" + fs::path_sep() }
        session::os_macos. { "" }
    };

    prefix + get_relative_to(
        get_absolute(cwd, output),
        get_absolute(cwd, lib))
}

// Find the relative path from one file to another
fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path {
    assert fs::path_is_absolute(abs1);
    assert fs::path_is_absolute(abs2);
    log #fmt("finding relative path from %s to %s",
             abs1, abs2);
    let normal1 = fs::normalize(abs1);
    let normal2 = fs::normalize(abs2);
    let split1 = str::split(normal1, os_fs::path_sep as u8);
    let split2 = str::split(normal2, os_fs::path_sep as u8);
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0u;
    assert len2 > 0u;

    let max_common_path = uint::min(len1, len2) - 1u;
    let start_idx = 0u;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1u;
    }

    let path = [];

    for each _ in uint::range(start_idx, len1 - 1u) {
        path += [".."];
    }

    path += vec::slice(split2, start_idx, len2 - 1u);

    if check vec::is_not_empty(path) {
        ret fs::connect_many(path);
    } else {
        ret ".";
    }
}

fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] {
    vec::map(bind get_absolute_rpath(cwd, _), libs)
}

fn get_absolute_rpath(cwd: fs::path, lib: fs::path) -> str {
    fs::dirname(get_absolute(cwd, lib))
}

fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path {
    if fs::path_is_absolute(lib) {
        lib
    } else {
        fs::connect(cwd, lib)
    }
}

fn get_install_prefix_rpath(cwd: fs::path, target_triple: str) -> str {
    let install_prefix = #env("CFG_PREFIX");

    if install_prefix == "" {
        fail "rustc compiled without CFG_PREFIX environment variable";
    }

    let path = [install_prefix]
        + filesearch::relative_target_lib_path(target_triple);
    check vec::is_not_empty(path);
    get_absolute(cwd, fs::connect_many(path))
}

fn minimize_rpaths(rpaths: [str]) -> [str] {
    let set = map::new_str_hash::<()>();
    let minimized = [];
    for rpath in rpaths {
        if !set.contains_key(rpath) {
            minimized += [rpath];
            set.insert(rpath, ());
        }
    }
    ret minimized;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(test)]
mod test {
    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(["path1", "path2"]);
        assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"];
    }

    #[test]
    fn test_get_absolute1() {
        let cwd = "/dir";
        let lib = "some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/dir/some/path/lib";
    }

    #[test]
    fn test_get_absolute2() {
        let cwd = "/dir";
        let lib = "/some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/some/path/lib";
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert str::ends_with(res, #env("CFG_PREFIX")
                              + "/lib/rustc/triple/lib");
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert str::starts_with(res, "/");
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]);
        assert res == ["rpath1", "rpath2"];
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths(["1a", "2", "2", "1a", "4a",
                                   "1a", "2", "3", "4a", "3"]);
        assert res == ["1a", "2", "4a", "3"];
    }

    #[test]
    fn test_relative_to1() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to2() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/bin/../lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to3() {
        let p1 = "/usr/bin/whatever/rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../../lib/whatever";
    }

    #[test]
    fn test_relative_to4() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib/whatever";
    }

    #[test]
    fn test_relative_to5() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/../mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to6() {
        let p1 = "/1";
        let p2 = "/2/3";
        let res = get_relative_to(p1, p2);
        assert res == "2";
    }

    #[test]
    fn test_relative_to7() {
        let p1 = "/1/2";
        let p2 = "/3";
        let res = get_relative_to(p1, p2);
        assert res == "..";
    }

    #[test]
    fn test_relative_to8() {
        let p1 = "/home/brian/Dev/rust/build/"
            + "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
        let p2 = "/home/brian/Dev/rust/build/stage2/bin/.."
            + "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
        let res = get_relative_to(p1, p2);
        assert res == ".";
    }

    #[test]
    #[cfg(target_os = "linux")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_linux,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_macos,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "../lib";
    }

    #[test]
    fn test_get_absolute_rpath() {
        let res = get_absolute_rpath("/usr", "lib/libstd.so");
        assert res == "/usr/lib";
    }
}
<commit_msg>Mac uses @executable_path instead of $ORIGIN<commit_after>import std::os;
import std::fs;
import std::os_fs;
import std::vec;
import std::map;
import std::str;
import std::uint;
import metadata::cstore;
import driver::session;
import util::filesearch;

// FIXME #721: Despite the compiler warning, test does exist and needs
// to be exported
export get_rpath_flags, test;

fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
    let os = sess.get_targ_cfg().os;

    // No rpath on windows
    if os == session::os_win32 {
        ret [];
    }

    log "preparing the RPATH!";

    let cwd = os::getcwd();
    let sysroot = sess.filesearch().sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.get_cstore());
    // We don't currently rpath native libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = libs + [get_sysroot_absolute_rt_lib(sess)];

    let target_triple = sess.get_opts().target_triple;
    let rpaths = get_rpaths(os, cwd, sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path {
    let path = [sess.filesearch().sysroot()]
        + filesearch::relative_target_lib_path(
            sess.get_opts().target_triple)
        + [os::dylib_filename("rustrt")];
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn rpaths_to_flags(rpaths: [str]) -> [str] {
    vec::map({ |rpath| #fmt("-Wl,-rpath,%s",rpath)}, rpaths)
}

fn get_rpaths(os: session::os, cwd: fs::path, sysroot: fs::path,
              output: fs::path, libs: [fs::path],
              target_triple: str) -> [str] {
    log #fmt("cwd: %s", cwd);
    log #fmt("sysroot: %s", sysroot);
    log #fmt("output: %s", output);
    log #fmt("libs:");
    for libpath in libs {
        log #fmt("    %s", libpath);
    }
    log #fmt("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, cwd, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(cwd, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = [get_install_prefix_rpath(cwd, target_triple)];

    fn log_rpaths(desc: str, rpaths: [str]) {
        log #fmt("%s rpaths:", desc);
        for rpath in rpaths {
            log #fmt("    %s", rpath);
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("absolute", abs_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths;

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    ret rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 cwd: fs::path,
                                 output: fs::path,
                                 libs: [fs::path]) -> [str] {
    vec::map(bind get_rpath_relative_to_output(os, cwd, output, _), libs)
}

fn get_rpath_relative_to_output(os: session::os,
                                cwd: fs::path,
                                output: fs::path,
                                lib: fs::path) -> str {
    // Mac doesn't appear to support $ORIGIN
    let prefix = alt os {
        session::os_linux. { "$ORIGIN" + fs::path_sep() }
        session::os_macos. { "@executable_path" + fs::path_sep() }
    };

    prefix + get_relative_to(
        get_absolute(cwd, output),
        get_absolute(cwd, lib))
}

// Find the relative path from one file to another
fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path {
    assert fs::path_is_absolute(abs1);
    assert fs::path_is_absolute(abs2);
    log #fmt("finding relative path from %s to %s",
             abs1, abs2);
    let normal1 = fs::normalize(abs1);
    let normal2 = fs::normalize(abs2);
    let split1 = str::split(normal1, os_fs::path_sep as u8);
    let split2 = str::split(normal2, os_fs::path_sep as u8);
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0u;
    assert len2 > 0u;

    let max_common_path = uint::min(len1, len2) - 1u;
    let start_idx = 0u;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1u;
    }

    let path = [];

    for each _ in uint::range(start_idx, len1 - 1u) {
        path += [".."];
    }

    path += vec::slice(split2, start_idx, len2 - 1u);

    if check vec::is_not_empty(path) {
        ret fs::connect_many(path);
    } else {
        ret ".";
    }
}

fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] {
    vec::map(bind get_absolute_rpath(cwd, _), libs)
}

fn get_absolute_rpath(cwd: fs::path, lib: fs::path) -> str {
    fs::dirname(get_absolute(cwd, lib))
}

fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path {
    if fs::path_is_absolute(lib) {
        lib
    } else {
        fs::connect(cwd, lib)
    }
}

fn get_install_prefix_rpath(cwd: fs::path, target_triple: str) -> str {
    let install_prefix = #env("CFG_PREFIX");

    if install_prefix == "" {
        fail "rustc compiled without CFG_PREFIX environment variable";
    }

    let path = [install_prefix]
        + filesearch::relative_target_lib_path(target_triple);
    check vec::is_not_empty(path);
    get_absolute(cwd, fs::connect_many(path))
}

fn minimize_rpaths(rpaths: [str]) -> [str] {
    let set = map::new_str_hash::<()>();
    let minimized = [];
    for rpath in rpaths {
        if !set.contains_key(rpath) {
            minimized += [rpath];
            set.insert(rpath, ());
        }
    }
    ret minimized;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(test)]
mod test {
    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(["path1", "path2"]);
        assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"];
    }

    #[test]
    fn test_get_absolute1() {
        let cwd = "/dir";
        let lib = "some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/dir/some/path/lib";
    }

    #[test]
    fn test_get_absolute2() {
        let cwd = "/dir";
        let lib = "/some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/some/path/lib";
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert str::ends_with(res, #env("CFG_PREFIX")
                              + "/lib/rustc/triple/lib");
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert str::starts_with(res, "/");
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]);
        assert res == ["rpath1", "rpath2"];
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths(["1a", "2", "2", "1a", "4a",
                                   "1a", "2", "3", "4a", "3"]);
        assert res == ["1a", "2", "4a", "3"];
    }

    #[test]
    fn test_relative_to1() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to2() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/bin/../lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to3() {
        let p1 = "/usr/bin/whatever/rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../../lib/whatever";
    }

    #[test]
    fn test_relative_to4() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib/whatever";
    }

    #[test]
    fn test_relative_to5() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/../mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to6() {
        let p1 = "/1";
        let p2 = "/2/3";
        let res = get_relative_to(p1, p2);
        assert res == "2";
    }

    #[test]
    fn test_relative_to7() {
        let p1 = "/1/2";
        let p2 = "/3";
        let res = get_relative_to(p1, p2);
        assert res == "..";
    }

    #[test]
    fn test_relative_to8() {
        let p1 = "/home/brian/Dev/rust/build/"
            + "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
        let p2 = "/home/brian/Dev/rust/build/stage2/bin/.."
            + "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
        let res = get_relative_to(p1, p2);
        assert res == ".";
    }

    #[test]
    #[cfg(target_os = "linux")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_linux,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_macos,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "@executable_path/../lib";
    }

    #[test]
    fn test_get_absolute_rpath() {
        let res = get_absolute_rpath("/usr", "lib/libstd.so");
        assert res == "/usr/lib";
    }
}
<|endoftext|>