<commit_before>//! `harfbuzz_rs` is a high-level interface to HarfBuzz, exposing its most important functionality
//! in a safe manner using Rust.
//!
//! # What is HarfBuzz?
//! HarfBuzz is a library for performing complex text layout. It does not perform any drawing. This
//! is quite a low-level operation. If you want to simply draw some text on the screen choose
//! another library. However if you want to build a library for drawing text on some canvas or
//! need a lot of control on advanced text layout then this is the right library to use.
//!
//! # Getting Started
//!
//! To shape a simple string of text you just create a `Font` from a font file, fill a `Buffer`
//! with some text and call the `shape` function.
//!
//! ```
//! use harfbuzz_rs::*;
//!
//! # fn try_main() -> Result<(), std::io::Error> {
//!
//! let path = "path/to/some/font_file.otf";
//! let index = 0; //< face index in the font file
//! # let path = "testfiles/SourceSansVariable-Roman.ttf";
//! let face = Face::from_file(path, index)?;
//! let mut font = Font::new(face);
//!
//! let buffer = UnicodeBuffer::new().add_str("Hello World!");
//! let output = shape(&font, buffer, &[]);
//!
//! // The results of the shaping operation are stored in the `output` buffer.
//!
//! let positions = output.get_glyph_positions();
//! let infos = output.get_glyph_infos();
//!
//! # assert_eq!(positions.len(), 12);
//! assert_eq!(positions.len(), infos.len());
//!
//! // iterate over the shaped glyphs
//! for (position, info) in positions.iter().zip(infos) {
//!     let gid = info.codepoint;
//!     let cluster = info.cluster;
//!     let x_advance = position.x_advance;
//!     let x_offset = position.x_offset;
//!     let y_offset = position.y_offset;
//!
//!     // Here you would usually draw the glyphs.
//!     println!("gid{:?}={:?}@{:?},{:?}+{:?}", gid, cluster, x_advance, x_offset, y_offset);
//! }
//!
//! # Ok(())
//! # }
//! #
//! # try_main().unwrap();
//! ```
//! This should print out something similar to the following:
//!
//! ```text
//! gid41=0@741,0+0
//! gid70=1@421,0+0
//! gid77=2@258,0+0
//! gid77=3@253,0+0
//! gid80=4@510,0+0
//! gid1=5@227,0+0
//! gid56=6@874,0+0
//! gid80=7@498,0+0
//! gid83=8@367,0+0
//! gid77=9@253,0+0
//! gid69=10@528,0+0
//! gid2=11@276,0+0
//! ```
#![deny(missing_debug_implementations)]

/// Reexported `harfbuzz_sys` crate to directly access the C API whenever no
/// adequate wrapper is provided.
// This will hopefully not cause backwards compability concerns since harfbuzz
// tries to be backwards compatible.
use harfbuzz_sys as hb;
#[macro_use]
extern crate bitflags;

mod blob;
mod buffer;
mod common;
mod face;
mod font;
pub mod font_funcs;

#[cfg(feature = "rusttype")]
pub mod rusttype;

pub use crate::blob::*;
pub use crate::buffer::*;
pub use crate::common::*;
pub use crate::face::*;
pub use crate::font::*;

use std::ops::{Bound, RangeBounds};
use std::os::raw::c_uint;

pub(crate) fn start_end_range(range: impl RangeBounds<usize>) -> (c_uint, c_uint) {
    // We have to do careful bounds checking since c_uint may be of
    // different sizes on different platforms. We do assume that
    // sizeof(usize) >= sizeof(c_uint).
    const MAX_UINT: usize = c_uint::max_value() as usize;
    let start = match range.start_bound() {
        Bound::Included(&included) => included.min(MAX_UINT) as c_uint,
        Bound::Excluded(&excluded) => excluded.min(MAX_UINT - 1) as c_uint + 1,
        Bound::Unbounded => 0,
    };
    let end = match range.end_bound() {
        Bound::Included(&included) => included.saturating_add(1).min(MAX_UINT) as c_uint,
        Bound::Excluded(&excluded) => excluded.min(MAX_UINT) as c_uint,
        Bound::Unbounded => c_uint::max_value(),
    };
    (start, end)
}
/// A feature tag with an accompanying range specifying on which subslice of
/// `shape`s input it should be applied.
///
/// You can pass a slice of `Feature`s to `shape` that will be activated for the
/// corresponding slices of input.
///
/// # Examples
///
/// Shape some text using the `calt` (Contextual Alternatives) feature.
///
/// ```
/// use harfbuzz_rs::{Face, Font, UnicodeBuffer, shape, Feature, Tag};
///
/// let path = "testfiles/SourceSansVariable-Roman.ttf";
/// let face = Face::from_file(path, 0).expect("could not load face");
/// let font = Font::new(face);
///
/// let buffer = UnicodeBuffer::new().add_str("Hello World!");
///
/// // contextual alternatives feature
/// let feature_tag = b"calt";
///
/// // use the feature on the entire input
/// let feature_range = 0..;
/// let feature = Feature::new(feature_tag, 0, feature_range);
///
/// let output = shape(&font, buffer, &[feature]);
/// ```
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Feature(hb::hb_feature_t);

impl Feature {
    /// Create a new `Feature` struct.
    ///
    /// The feature will be applied with the given value to all glyphs which are
    /// in clusters contained in `range`.
    ///
    /// # Arguments
    ///
    /// - `tag`: The OpenType feature tag to use.
    /// - `value`: Some OpenType features accept different values to change
    ///   their behaviour.
    /// - `range`: The cluster range that should be affected by this feature.
    pub fn new(tag: impl Into<Tag>, value: u32, range: impl RangeBounds<usize>) -> Feature {
        let (start, end) = start_end_range(range);
        Feature(hb::hb_feature_t {
            tag: tag.into().0,
            value,
            start,
            end,
        })
    }

    pub fn tag(&self) -> Tag {
        Tag(self.0.tag)
    }

    pub fn value(&self) -> u32 {
        self.0.value
    }

    pub fn start(&self) -> usize {
        self.0.start as usize
    }

    pub fn end(&self) -> usize {
        self.0.end as usize
    }
}

/// Shape the contents of the buffer using the provided font and activating all
/// OpenType features given in `features`.
///
/// This function consumes the `buffer` and returns a `GlyphBuffer` containing
/// the resulting glyph indices and the corresponding positioning information.
/// Once all the information from the `GlyphBuffer` has been processed as
/// necessary you can reuse the `GlyphBuffer` as an `UnicodeBuffer` (using
/// `GlyphBuffer::clear_contents`) and use that to call `shape` again with new
/// data.
///
/// By default some basic OpenType features are enabled according to the
/// language and the script set in the buffer.
///
/// # Arguments
/// - `font` – a reference to the harfbuzz font used to shape the text.
/// - `buffer` – a `UnicodeBuffer` that is filled with the text to be shaped and
/// also contains metadata about the text in the form of segment properties.
/// - `features` – a slice of additional features to activate
pub fn shape(font: &Font<'_>, buffer: UnicodeBuffer, features: &[Feature]) -> GlyphBuffer {
    let buffer = buffer.guess_segment_properties();
    unsafe {
        hb::hb_shape(
            font.as_raw(),
            buffer.0.as_raw(),
            features.as_ptr() as *mut _,
            features.len() as u32,
        )
    };
    GlyphBuffer(buffer.0)
}

#[cfg(test)]
mod tests {
    use std::mem::{align_of, size_of};

    pub(crate) fn assert_memory_layout_equal<T, U>() {
        assert_eq!(size_of::<T>(), size_of::<U>());
        assert_eq!(align_of::<T>(), align_of::<U>());
    }

    #[test]
    fn it_works() {}

    fn assert_feature(feat: Feature, tag: Tag, value: u32, start: usize, end: usize) {
        assert_eq!(feat.tag(), tag);
        assert_eq!(feat.value(), value);
        assert_eq!(feat.start(), start);
        assert_eq!(feat.end(), end);
    }

    use super::{Feature, Tag};
    #[test]
    fn feature_new() {
        let tag = b"abcd".into();
        const UINT_MAX: usize = std::os::raw::c_uint::max_value() as usize;

        let feature = Feature::new(tag, 100, 2..100);
        assert_feature(feature, tag, 100, 2, 100);

        let feature = Feature::new(tag, 100, 2..=100);
        assert_feature(feature, tag, 100, 2, 101);

        let feature = Feature::new(tag, 100, 2..);
        assert_feature(feature, tag, 100, 2, UINT_MAX);

        let feature = Feature::new(tag, 100, ..100);
        assert_feature(feature, tag, 100, 0, 100);

        let feature = Feature::new(tag, 100, ..=100);
        assert_feature(feature, tag, 100, 0, 101);

        let feature = Feature::new(tag, 100, ..);
        assert_feature(feature, tag, 100, 0, UINT_MAX);
    }
}
<commit_msg>add Variation struct and set_variations function<commit_after>//! `harfbuzz_rs` is a high-level interface to HarfBuzz, exposing its most important functionality
//! in a safe manner using Rust.
//!
//! # What is HarfBuzz?
//! HarfBuzz is a library for performing complex text layout. It does not perform any drawing. This
//! is quite a low-level operation. If you want to simply draw some text on the screen choose
//! another library. However if you want to build a library for drawing text on some canvas or
//! need a lot of control on advanced text layout then this is the right library to use.
//!
//! # Getting Started
//!
//! To shape a simple string of text you just create a `Font` from a font file, fill a `Buffer`
//! with some text and call the `shape` function.
//!
//! ```
//! use harfbuzz_rs::*;
//!
//! # fn try_main() -> Result<(), std::io::Error> {
//!
//! let path = "path/to/some/font_file.otf";
//! let index = 0; //< face index in the font file
//! # let path = "testfiles/SourceSansVariable-Roman.ttf";
//! let face = Face::from_file(path, index)?;
//! let mut font = Font::new(face);
//!
//! let buffer = UnicodeBuffer::new().add_str("Hello World!");
//! let output = shape(&font, buffer, &[]);
//!
//! // The results of the shaping operation are stored in the `output` buffer.
//!
//! let positions = output.get_glyph_positions();
//! let infos = output.get_glyph_infos();
//!
//! # assert_eq!(positions.len(), 12);
//! assert_eq!(positions.len(), infos.len());
//!
//! // iterate over the shaped glyphs
//! for (position, info) in positions.iter().zip(infos) {
//!     let gid = info.codepoint;
//!     let cluster = info.cluster;
//!     let x_advance = position.x_advance;
//!     let x_offset = position.x_offset;
//!     let y_offset = position.y_offset;
//!
//!     // Here you would usually draw the glyphs.
//!     println!("gid{:?}={:?}@{:?},{:?}+{:?}", gid, cluster, x_advance, x_offset, y_offset);
//! }
//!
//! # Ok(())
//! # }
//! #
//! # try_main().unwrap();
//! ```
//! This should print out something similar to the following:
//!
//! ```text
//! gid41=0@741,0+0
//! gid70=1@421,0+0
//! gid77=2@258,0+0
//! gid77=3@253,0+0
//! gid80=4@510,0+0
//! gid1=5@227,0+0
//! gid56=6@874,0+0
//! gid80=7@498,0+0
//! gid83=8@367,0+0
//! gid77=9@253,0+0
//! gid69=10@528,0+0
//! gid2=11@276,0+0
//! ```
#![deny(missing_debug_implementations)]

/// Reexported `harfbuzz_sys` crate to directly access the C API whenever no
/// adequate wrapper is provided.
// This will hopefully not cause backwards compability concerns since harfbuzz
// tries to be backwards compatible.
use harfbuzz_sys as hb;
#[macro_use]
extern crate bitflags;

mod blob;
mod buffer;
mod common;
mod face;
mod font;
pub mod font_funcs;

#[cfg(feature = "rusttype")]
pub mod rusttype;

pub use crate::blob::*;
pub use crate::buffer::*;
pub use crate::common::*;
pub use crate::face::*;
pub use crate::font::*;

use std::ops::{Bound, RangeBounds};
use std::os::raw::c_uint;

pub(crate) fn start_end_range(range: impl RangeBounds<usize>) -> (c_uint, c_uint) {
    // We have to do careful bounds checking since c_uint may be of
    // different sizes on different platforms. We do assume that
    // sizeof(usize) >= sizeof(c_uint).
    const MAX_UINT: usize = c_uint::max_value() as usize;
    let start = match range.start_bound() {
        Bound::Included(&included) => included.min(MAX_UINT) as c_uint,
        Bound::Excluded(&excluded) => excluded.min(MAX_UINT - 1) as c_uint + 1,
        Bound::Unbounded => 0,
    };
    let end = match range.end_bound() {
        Bound::Included(&included) => included.saturating_add(1).min(MAX_UINT) as c_uint,
        Bound::Excluded(&excluded) => excluded.min(MAX_UINT) as c_uint,
        Bound::Unbounded => c_uint::max_value(),
    };
    (start, end)
}
/// A feature tag with an accompanying range specifying on which subslice of
/// `shape`s input it should be applied.
///
/// You can pass a slice of `Feature`s to `shape` that will be activated for the
/// corresponding slices of input.
///
/// # Examples
///
/// Shape some text using the `calt` (Contextual Alternatives) feature.
///
/// ```
/// use harfbuzz_rs::{Face, Font, UnicodeBuffer, shape, Feature, Tag};
///
/// let path = "testfiles/SourceSansVariable-Roman.ttf";
/// let face = Face::from_file(path, 0).expect("could not load face");
/// let font = Font::new(face);
///
/// let buffer = UnicodeBuffer::new().add_str("Hello World!");
///
/// // contextual alternatives feature
/// let feature_tag = b"calt";
///
/// // use the feature on the entire input
/// let feature_range = 0..;
/// let feature = Feature::new(feature_tag, 0, feature_range);
///
/// let output = shape(&font, buffer, &[feature]);
/// ```
///
///
    /// Create a new `variation` struct.
    ///
    ///
    /// # Arguments
    ///
    /// - `tag`: The OpenType variation tag to use.
    /// - `value`: Some OpenType variant accept different values to change
    ///   their behaviour.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Variation(hb::hb_variation_t);

impl Variation{
    pub fn new(tag: impl Into<Tag>, value: f32) -> Variation {
        Variation(hb::hb_variation_t {
            tag: tag.into().0,
            value,

        })
    }

    pub fn tag(&self) -> Tag {
        Tag(self.0.tag)
    }

    pub fn value(&self) -> f32 {
        self.0.value
    }
}

////
/// Set font variation
/// eg.
/// let variation_vec : Vec<Variation> = vec![Variation::new(b"wght", 800.0), Variation::new(b"wdth", 30.0)];
/// set_variations(&font, &variation_vec);
///
pub fn set_variations(font: &Font<'_>,  features: &[Variation]) {
    unsafe {
        hb::hb_font_set_variations(
            font.as_raw(),
            features.as_ptr() as *mut _,
            features.len() as u32,
        )
    };
}

#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Feature(hb::hb_feature_t);

impl Feature {
    /// Create a new `Feature` struct.
    ///
    /// The feature will be applied with the given value to all glyphs which are
    /// in clusters contained in `range`.
    ///
    /// # Arguments
    ///
    /// - `tag`: The OpenType feature tag to use.
    /// - `value`: Some OpenType features accept different values to change
    ///   their behaviour.
    /// - `range`: The cluster range that should be affected by this feature.
    pub fn new(tag: impl Into<Tag>, value: u32, range: impl RangeBounds<usize>) -> Feature {
        let (start, end) = start_end_range(range);
        Feature(hb::hb_feature_t {
            tag: tag.into().0,
            value,
            start,
            end,
        })
    }

    pub fn tag(&self) -> Tag {
        Tag(self.0.tag)
    }

    pub fn value(&self) -> u32 {
        self.0.value
    }

    pub fn start(&self) -> usize {
        self.0.start as usize
    }

    pub fn end(&self) -> usize {
        self.0.end as usize
    }
}

/// Shape the contents of the buffer using the provided font and activating all
/// OpenType features given in `features`.
///
/// This function consumes the `buffer` and returns a `GlyphBuffer` containing
/// the resulting glyph indices and the corresponding positioning information.
/// Once all the information from the `GlyphBuffer` has been processed as
/// necessary you can reuse the `GlyphBuffer` as an `UnicodeBuffer` (using
/// `GlyphBuffer::clear_contents`) and use that to call `shape` again with new
/// data.
///
/// By default some basic OpenType features are enabled according to the
/// language and the script set in the buffer.
///
/// # Arguments
/// - `font` – a reference to the harfbuzz font used to shape the text.
/// - `buffer` – a `UnicodeBuffer` that is filled with the text to be shaped and
/// also contains metadata about the text in the form of segment properties.
/// - `features` – a slice of additional features to activate
pub fn shape(font: &Font<'_>, buffer: UnicodeBuffer, features: &[Feature]) -> GlyphBuffer {
    let buffer = buffer.guess_segment_properties();
    unsafe {
        hb::hb_shape(
            font.as_raw(),
            buffer.0.as_raw(),
            features.as_ptr() as *mut _,
            features.len() as u32,
        )
    };
    GlyphBuffer(buffer.0)
}

#[cfg(test)]
mod tests {
    use std::mem::{align_of, size_of};

    pub(crate) fn assert_memory_layout_equal<T, U>() {
        assert_eq!(size_of::<T>(), size_of::<U>());
        assert_eq!(align_of::<T>(), align_of::<U>());
    }

    #[test]
    fn it_works() {}

    fn assert_feature(feat: Feature, tag: Tag, value: u32, start: usize, end: usize) {
        assert_eq!(feat.tag(), tag);
        assert_eq!(feat.value(), value);
        assert_eq!(feat.start(), start);
        assert_eq!(feat.end(), end);
    }

    use super::{Feature, Tag};
    #[test]
    fn feature_new() {
        let tag = b"abcd".into();
        const UINT_MAX: usize = std::os::raw::c_uint::max_value() as usize;

        let feature = Feature::new(tag, 100, 2..100);
        assert_feature(feature, tag, 100, 2, 100);

        let feature = Feature::new(tag, 100, 2..=100);
        assert_feature(feature, tag, 100, 2, 101);

        let feature = Feature::new(tag, 100, 2..);
        assert_feature(feature, tag, 100, 2, UINT_MAX);

        let feature = Feature::new(tag, 100, ..100);
        assert_feature(feature, tag, 100, 0, 100);

        let feature = Feature::new(tag, 100, ..=100);
        assert_feature(feature, tag, 100, 0, 101);

        let feature = Feature::new(tag, 100, ..);
        assert_feature(feature, tag, 100, 0, UINT_MAX);
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate hyper_native_tls;
extern crate pbr;
extern crate regex;

use pbr::ProgressBar;
use std::{process,str};
use std::collections::HashMap;
use hyper::client::response::Response;
use hyper::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use hyper::header::ContentLength;
use std::io::Read;
use std::io::prelude::*;
use std::fs::File;
use regex::Regex;

pub struct Info {
    pub url: String,
    pub title: String,
    //pub rating: ,
    pub viewcount: u32,
    pub author: String,
    pub length: u32,
    pub duration: String,
    pub likes: u32,
    pub dislikes: u32,
    pub description: String,
    //pub streams: ,
    //pub audiostreams: ,
    //pub allstreams: ,
}

pub fn new(video_url: &str) -> Info {
    //Regex for youtube URLs.
    let url_regex = Regex::new(r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*").unwrap();
    let mut vid = "https://www.youtube.com/watch?v=DjMkfARvGE8";
    if url_regex.is_match(vid) {
        let vid_split = url_regex.captures(vid).unwrap();
        vid = vid_split.get(1).unwrap().as_str();
    }
    let url = format!("https://youtube.com/get_video_info?video_id={}", vid);
    download(&url);
    Info { video_url: video_url.to_string() }
}

fn download(url: &str) {
    let mut response = send_request(url);
    let mut response_str = String::new();
    response.read_to_string(&mut response_str).unwrap();
    let hq = parse_url(&response_str);

    if hq["status"] != "ok" {
        println!("Video not found!");
        process::exit(1);
    }

    // get video info
    let streams: Vec<&str> = hq["url_encoded_fmt_stream_map"]
        .split(',')
        .collect();

    // list of available qualities
    let mut qualities: HashMap<i32, (String, String)> = HashMap::new();
    for (i, url) in streams.iter().enumerate() {
        let quality = parse_url(url);
        let extension = quality["type"]
            .split('/')
            .nth(1)
            .unwrap()
            .split(';')
            .next()
            .unwrap();
        qualities.insert(i as i32,
                         (quality["url"].to_string(), extension.to_owned()));
        println!("{}- {} {}",
                 i,
                 quality["quality"],
                 quality["type"]);
    }
}

fn send_request(url: &str) -> Response {
    let ssl = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);
    client.get(url).send().unwrap_or_else(|e| {
        println!("Network request failed: {}", e);
        process::exit(1);
    })
}

fn parse_url(query: &str) -> HashMap<String, String> {
    let u = format!("{}{}", "http://e.com?", query);
    let parsed_url = hyper::Url::parse(&u).unwrap();
    parsed_url.query_pairs().into_owned().collect()
}
<commit_msg>Add more pub variables<commit_after>extern crate hyper;
extern crate hyper_native_tls;
extern crate pbr;
extern crate regex;

use pbr::ProgressBar;
use std::{process,str};
use std::collections::HashMap;
use hyper::client::response::Response;
use hyper::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use hyper::header::ContentLength;
use std::io::Read;
use std::io::prelude::*;
use std::fs::File;
use regex::Regex;

pub struct Info {
    pub url: String,
    //pub title: String,
    //pub rating: ,
    //pub viewcount: u32,
    //pub author: String,
    //pub length: u32,
    //pub duration: String,
    //pub likes: u32,
    //pub dislikes: u32,
    //pub description: String,
    //pub streams: ,
    //pub audiostreams: ,
    //pub allstreams: ,
}

pub fn new(url: &str) -> Info {
    //Regex for youtube URLs.
    let url_regex = Regex::new(r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*").unwrap();
    let mut vid = url;
    if url_regex.is_match(vid) {
        let vid_split = url_regex.captures(vid).unwrap();
        vid = vid_split.get(1).unwrap().as_str();
    }
    let url = format!("https://youtube.com/get_video_info?video_id={}", vid);
    download(&url);
    Info { url: video_url.to_string() }
}

fn download(url: &str) {
    let mut response = send_request(url);
    let mut response_str = String::new();
    response.read_to_string(&mut response_str).unwrap();
    let hq = parse_url(&response_str);

    if hq["status"] != "ok" {
        println!("Video not found!");
        process::exit(1);
    }

    // get video info
    let streams: Vec<&str> = hq["url_encoded_fmt_stream_map"]
        .split(',')
        .collect();

    // list of available qualities
    let mut qualities: HashMap<i32, (String, String)> = HashMap::new();
    for (i, url) in streams.iter().enumerate() {
        let quality = parse_url(url);
        let extension = quality["type"]
            .split('/')
            .nth(1)
            .unwrap()
            .split(';')
            .next()
            .unwrap();
        qualities.insert(i as i32,
                         (quality["url"].to_string(), extension.to_owned()));
        println!("{}- {} {}",
                 i,
                 quality["quality"],
                 quality["type"]);
    }
}

fn send_request(url: &str) -> Response {
    let ssl = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);
    client.get(url).send().unwrap_or_else(|e| {
        println!("Network request failed: {}", e);
        process::exit(1);
    })
}

fn parse_url(query: &str) -> HashMap<String, String> {
    let u = format!("{}{}", "http://e.com?", query);
    let parsed_url = hyper::Url::parse(&u).unwrap();
    parsed_url.query_pairs().into_owned().collect()
}
<|endoftext|>


<commit_before>
#[cfg(test)]
#[macro_use]
extern crate lazy_static;

use std::ptr;
use std::mem;
use std::cmp::{Ord, Ordering};

pub trait MapInPlace<A, B>: Sized {
    /// Should be of the same base type as the implementor.
    /// E.g. `Vec<B>` when implementing for `Vec<A>`
    type Output;

    /// Apply a mapping function to `self` without allocating.
    /// Makes best effort to maintain the invariant
    ///
    /// `self.as_ptr() as *const () == self.map_in_place(..).as_ptr() as *const ()`
    ///
    /// An example of a case where this isn't possible is for Vec where B is zero-sized but A is not.
    fn map_in_place<F>(self, f: F) -> Self::Output where F: FnMut(A) -> B;
}

unsafe fn map_in_place<A, B, F>(ptr_a: *const A, ptr_b: *mut B, len: usize, mut f: F)
    where F: FnMut(A) -> B
{
    for i in 0..len {
        let ptr_a = ptr_a.offset(i as isize);
        let ptr_b = ptr_b.offset(i as isize);

        ptr::write(ptr_b, f(ptr::read(ptr_a)));
    }
}

impl<A, B> MapInPlace<A, B> for Vec<A> {
    type Output = Vec<B>;

    #[inline]
    fn map_in_place<F>(mut self, mut f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                // map_loop!();
                self.as_mut_slice().map_in_place(f);

                unsafe { mem::transmute(self) }
            }
            Ordering::Greater => {
                if b_size == 0 {
                    // doesn't preserve address invariant
                    let mut v = Vec::with_capacity(0);

                    for e in self.into_iter() {
                        v.push(f(e));
                    }

                    v
                } else {
                    let cap = self.capacity().checked_mul(a_size).map(|x| x / b_size).unwrap();
                    let ptr_a = self.as_ptr();
                    let ptr_b = ptr_a as *mut B;
                    let len = self.len();

                    unsafe {
                        map_in_place(ptr_a, ptr_b, len, f);
                        mem::forget(self);
                        Vec::from_raw_parts(ptr_b, len, cap)
                    }
                }
            }
            Ordering::Less => {
                panic!("map_in_place(Vec<A>): Size of A must be greater than or equal to size of B")
            }
        }
    }
}

impl<'a, A, B: 'a> MapInPlace<A, B> for &'a mut [A] {
    type Output = &'a mut [B];

    #[inline]
    fn map_in_place<F>(self, f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                let ptr_a = self.as_ptr();
                let ptr_b = ptr_a as *mut B;

                unsafe {
                    map_in_place(ptr_a, ptr_b, self.len(), f);
                    mem::transmute(self)
                }
            }
            _ => panic!("map_in_place(&mut [A]): Size of A must be equal to size of B"),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::MapInPlace;

    #[test]
    fn same_size_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn different_sizes_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_vec() {
        #[derive(Debug)]
        struct Zst;

        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    fn nzst_to_zst_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_vec() {
        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    // //////

    #[test]
    fn same_size_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    #[should_panic]
    fn different_sizes_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_slice() {
        #[derive(Debug)]
        struct Zst;

        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    #[should_panic]
    fn nzst_to_zst_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_slice() {
        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }
}
<commit_msg>Add dropping test<commit_after>
#[cfg(test)]
#[macro_use]
extern crate lazy_static;

use std::ptr;
use std::mem;
use std::cmp::{Ord, Ordering};

pub trait MapInPlace<A, B>: Sized {
    /// Should be of the same base type as the implementor.
    /// E.g. `Vec<B>` when implementing for `Vec<A>`
    type Output;

    /// Apply a mapping function to `self` without allocating.
    /// Makes best effort to maintain the invariant
    ///
    /// `self.as_ptr() as *const () == self.map_in_place(..).as_ptr() as *const ()`
    ///
    /// An example of a case where this isn't possible is for Vec where B is zero-sized but A is not.
    fn map_in_place<F>(self, f: F) -> Self::Output where F: FnMut(A) -> B;
}

unsafe fn map_in_place<A, B, F>(ptr_a: *const A, ptr_b: *mut B, len: usize, mut f: F)
    where F: FnMut(A) -> B
{
    for i in 0..len {
        let ptr_a = ptr_a.offset(i as isize);
        let ptr_b = ptr_b.offset(i as isize);

        ptr::write(ptr_b, f(ptr::read(ptr_a)));
    }
}

impl<A, B> MapInPlace<A, B> for Vec<A> {
    type Output = Vec<B>;

    #[inline]
    fn map_in_place<F>(mut self, mut f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                // map_loop!();
                self.as_mut_slice().map_in_place(f);

                unsafe { mem::transmute(self) }
            }
            Ordering::Greater => {
                if b_size == 0 {
                    // doesn't preserve address invariant
                    let mut v = Vec::with_capacity(0);

                    for e in self.into_iter() {
                        v.push(f(e));
                    }

                    v
                } else {
                    let cap = self.capacity().checked_mul(a_size).map(|x| x / b_size).unwrap();
                    let ptr_a = self.as_ptr();
                    let ptr_b = ptr_a as *mut B;
                    let len = self.len();

                    unsafe {
                        map_in_place(ptr_a, ptr_b, len, f);
                        mem::forget(self);
                        Vec::from_raw_parts(ptr_b, len, cap)
                    }
                }
            }
            Ordering::Less => {
                panic!("map_in_place(Vec<A>): Size of A must be greater than or equal to size of B")
            }
        }
    }
}

impl<'a, A, B: 'a> MapInPlace<A, B> for &'a mut [A] {
    type Output = &'a mut [B];

    #[inline]
    fn map_in_place<F>(self, f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                let ptr_a = self.as_ptr();
                let ptr_b = ptr_a as *mut B;

                unsafe {
                    map_in_place(ptr_a, ptr_b, self.len(), f);
                    mem::transmute(self)
                }
            }
            _ => panic!("map_in_place(&mut [A]): Size of A must be equal to size of B"),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::MapInPlace;

    use std::mem;
    use std::sync::Mutex;

    #[test]
    fn vec_elements_drop() {
        lazy_static! {
            static ref DROPS: Mutex<Vec<String>> = Mutex::new(vec![]);
        }

        #[derive(Debug, PartialEq, Clone)]
        struct X(usize);

        impl Drop for X {
            fn drop(&mut self) {
                DROPS.lock().unwrap().push(format!("X({})", self.0));
            }
        }

        #[derive(Debug, PartialEq, Clone)]
        struct Y(usize);

        impl Drop for Y {
            fn drop(&mut self) {
                DROPS.lock().unwrap().push(format!("Y({})", self.0));
            }
        }

        assert_eq!(mem::size_of::<X>(), mem::size_of::<Y>()); // will use slice impl

        let v = vec![X(0), X(1), X(2), X(3)];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|X(v)| Y(v));

        {
            let drops = DROPS.lock().unwrap().clone();
            assert_eq!(drops, vec!["X(0)", "X(1)", "X(2)", "X(3)"]);
        }

        let ap = v.as_ptr() as *const ();
        let expected = vec![Y(0), Y(1), Y(2), Y(3)];

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, expected);

        mem::drop(v);

        {
            let drops = DROPS.lock().unwrap().clone();
            assert_eq!(drops,
                       vec!["X(0)", "X(1)", "X(2)", "X(3)", "Y(0)", "Y(1)", "Y(2)", "Y(3)"]);
        }

        mem::drop(expected);
    }

    #[test]
    fn same_size_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn different_sizes_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_vec() {
        #[derive(Debug)]
        struct Zst;

        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    fn nzst_to_zst_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_vec() {
        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    // //////

    #[test]
    fn same_size_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    #[should_panic]
    fn different_sizes_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_slice() {
        #[derive(Debug)]
        struct Zst;

        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    #[should_panic]
    fn nzst_to_zst_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_slice() {
        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }
}
<|endoftext|>


<commit_before>extern crate libc;
use std::ffi::CString;

#[allow(dead_code,
        non_snake_case,
        non_camel_case_types,
        non_upper_case_globals)]
pub mod libpq;

// Implementation of initialization and callbacks.

pub unsafe extern fn init(cb: *mut libpq::OutputPluginCallbacks) {
    (*cb).startup_cb = Some(startup);
    (*cb).begin_cb = Some(begin);
    (*cb).change_cb = Some(change);
    (*cb).commit_cb = Some(commit);
    (*cb).shutdown_cb = Some(shutdown);
}

#[allow(unused_variables)]
extern fn startup(ctx: *mut libpq::Struct_LogicalDecodingContext,
                  options: *mut libpq::OutputPluginOptions,
                  is_init: libpq::_bool) {
    unsafe {
        (*options).output_type = libpq::OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
    }
}

#[allow(unused_variables)]
extern fn begin(ctx: *mut libpq::Struct_LogicalDecodingContext,
                txn: *mut libpq::ReorderBufferTXN) {
    unsafe {
        let is_last = 1;                                  // True in C language
        let s = CString::new("{ \"begin\": %u }").unwrap();
        libpq::OutputPluginPrepareWrite(ctx, is_last);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
        libpq::OutputPluginWrite(ctx, is_last);
    }
}

#[allow(unused_variables)]
extern fn change(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 relation: libpq::Relation,
                 change: *mut libpq::ReorderBufferChange) {
    unsafe {
        let last = 1;                                     // True in C language

        libpq::OutputPluginPrepareWrite(ctx, 0);
        append_schema(relation, (*ctx).out);
        libpq::OutputPluginWrite(ctx, 0);
        libpq::OutputPluginPrepareWrite(ctx, last);
        append_change(relation, change, (*ctx).out);
        libpq::OutputPluginWrite(ctx, last);
    }
}

#[allow(unused_variables)]
extern fn commit(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 lsn: libpq::XLogRecPtr) {
    unsafe {
        let last = 1;                                     // True in C language
        let s = CString::new("{ \"commit\": %u, \"t\": \"%s\" }").unwrap();
        let t = libpq::timestamptz_to_str((*txn).commit_time);
        libpq::OutputPluginPrepareWrite(ctx, last);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid, t);
        libpq::OutputPluginWrite(ctx, last);
    }
}

#[allow(unused_variables)]
extern fn shutdown(ctx: *mut libpq::Struct_LogicalDecodingContext) {
  // Do nothing.
}

unsafe fn append_change(relation: libpq::Relation,
                        change: *mut libpq::ReorderBufferChange,
                        out: libpq::StringInfo) {
    let tuple_desc = (*relation).rd_att;
    let tuples = (*change).data.tp();
    let tuple_new = (*tuples).newtuple;
    let tuple_old = (*tuples).oldtuple;
    let token = match (*change).action {
        libpq::REORDER_BUFFER_CHANGE_INSERT => "insert",
        libpq::REORDER_BUFFER_CHANGE_UPDATE => "update",
        libpq::REORDER_BUFFER_CHANGE_DELETE => "delete",
        _ => panic!("Unrecognized change action!")
    };
    append("{ ", out);
    append("\"", out);
    append(token, out);
    append("\": ", out);
    append_tuple_buf_as_json(tuple_new, tuple_desc, out);
    if !tuple_old.is_null() {
        append(", \"@\": ", out);
        append_tuple_buf_as_json(tuple_old, tuple_desc, out);
    }
    append(" }", out);
}

unsafe fn append_tuple_buf_as_json(data: *mut libpq::ReorderBufferTupleBuf,
                                   desc: libpq::TupleDesc,
                                   out: libpq::StringInfo) {
    if !data.is_null() {
        let heap_tuple = &mut (*data).tuple;
        let datum = libpq::heap_copy_tuple_as_datum(heap_tuple, desc);
        let empty_oid: libpq::Oid = 0;
        let json = libpq::DirectFunctionCall1Coll(Some(row_to_json),
                                                  empty_oid,
                                                  datum);
        let ptr = json as *const libpq::Struct_varlena;
        let text = libpq::text_to_cstring(ptr);
        libpq::appendStringInfoString(out, text);
    } else {
        append("{}", out);
    }
}

unsafe fn append<T: Into<Vec<u8>>>(t: T, out: libpq::StringInfo) {
    libpq::appendStringInfoString(out, CString::new(t).unwrap().as_ptr());
}

unsafe fn append_schema(relation: libpq::Relation, out: libpq::StringInfo) {
    let relid = (*relation).rd_id;
    let form = (*relation).rd_rel;
    let tupdesc = (*relation).rd_att;
    let name = libpq::get_rel_name(relid);
    let ns = libpq::get_namespace_name(libpq::get_rel_namespace(relid));
    let qualified_name = libpq::quote_qualified_identifier(ns, name);
    append("{ \"table\": ", out);
    append("\"", out);
    libpq::appendStringInfoString(out, qualified_name);
    append("\"", out);
    append(", ", out);
    append(" \"schema\": ", out);
    append("[", out);
    let fmt = CString::new("{\"%s\":\"%s\"}").unwrap();
    let mut first: bool = true;
    for i in 0..(*tupdesc).natts {
        let attr = *(*tupdesc).attrs.offset(i as isize);
        let num = (*attr).attnum;
        if (*attr).attisdropped == 1 || num <= 0 {
            continue;
        }
        let col = libpq::get_attname(relid, num);
        let typ = libpq::format_type_be(libpq::get_atttype(relid, num));
        if !first {
            append(",", out);
        } else {
            first = false;
        }
        libpq::appendStringInfo(out, fmt.as_ptr(), col, typ);
    }
    append("]", out);
    append(" }", out);
}

extern fn row_to_json(fcinfo: libpq::FunctionCallInfo) -> libpq::Datum {
    // We wrap the unsafe call to make it safe.
    unsafe {
        libpq::row_to_json(fcinfo)
    }
}

// Symbols Postgres needs to find.

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn _PG_init() { }

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn
    _PG_output_plugin_init(cb: *mut libpq::OutputPluginCallbacks) { init(cb); }
<commit_msg>Clean up use of 0 and 1 as C booleans<commit_after>extern crate libc;
use std::ffi::CString;

#[allow(dead_code,
        non_snake_case,
        non_camel_case_types,
        non_upper_case_globals)]
pub mod libpq;

const CTRUE: libpq::_bool = 1;
const CFALSE: libpq::_bool = 0;

// Implementation of initialization and callbacks.

pub unsafe extern fn init(cb: *mut libpq::OutputPluginCallbacks) {
    (*cb).startup_cb = Some(startup);
    (*cb).begin_cb = Some(begin);
    (*cb).change_cb = Some(change);
    (*cb).commit_cb = Some(commit);
    (*cb).shutdown_cb = Some(shutdown);
}

#[allow(unused_variables)]
extern fn startup(ctx: *mut libpq::Struct_LogicalDecodingContext,
                  options: *mut libpq::OutputPluginOptions,
                  is_init: libpq::_bool) {
    unsafe {
        (*options).output_type = libpq::OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
    }
}

#[allow(unused_variables)]
extern fn begin(ctx: *mut libpq::Struct_LogicalDecodingContext,
                txn: *mut libpq::ReorderBufferTXN) {
    unsafe {
        let s = CString::new("{ \"begin\": %u }").unwrap();
        libpq::OutputPluginPrepareWrite(ctx, CTRUE);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
        libpq::OutputPluginWrite(ctx, CTRUE);
    }
}

#[allow(unused_variables)]
extern fn change(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 relation: libpq::Relation,
                 change: *mut libpq::ReorderBufferChange) {
    unsafe {
        libpq::OutputPluginPrepareWrite(ctx, CFALSE);
        append_schema(relation, (*ctx).out);
        libpq::OutputPluginWrite(ctx, CFALSE);
        libpq::OutputPluginPrepareWrite(ctx, CTRUE);
        append_change(relation, change, (*ctx).out);
        libpq::OutputPluginWrite(ctx, CTRUE);
    }
}

#[allow(unused_variables)]
extern fn commit(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 lsn: libpq::XLogRecPtr) {
    unsafe {
        let s = CString::new("{ \"commit\": %u, \"t\": \"%s\" }").unwrap();
        let t = libpq::timestamptz_to_str((*txn).commit_time);
        libpq::OutputPluginPrepareWrite(ctx, CTRUE);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid, t);
        libpq::OutputPluginWrite(ctx, CTRUE);
    }
}

#[allow(unused_variables)]
extern fn shutdown(ctx: *mut libpq::Struct_LogicalDecodingContext) {
  // Do nothing.
}

unsafe fn append_change(relation: libpq::Relation,
                        change: *mut libpq::ReorderBufferChange,
                        out: libpq::StringInfo) {
    let tuple_desc = (*relation).rd_att;
    let tuples = (*change).data.tp();
    let tuple_new = (*tuples).newtuple;
    let tuple_old = (*tuples).oldtuple;
    let token = match (*change).action {
        libpq::REORDER_BUFFER_CHANGE_INSERT => "insert",
        libpq::REORDER_BUFFER_CHANGE_UPDATE => "update",
        libpq::REORDER_BUFFER_CHANGE_DELETE => "delete",
        _ => panic!("Unrecognized change action!")
    };
    append("{ ", out);
    append("\"", out);
    append(token, out);
    append("\": ", out);
    append_tuple_buf_as_json(tuple_new, tuple_desc, out);
    if !tuple_old.is_null() {
        append(", \"@\": ", out);
        append_tuple_buf_as_json(tuple_old, tuple_desc, out);
    }
    append(" }", out);
}

unsafe fn append_tuple_buf_as_json(data: *mut libpq::ReorderBufferTupleBuf,
                                   desc: libpq::TupleDesc,
                                   out: libpq::StringInfo) {
    if !data.is_null() {
        let heap_tuple = &mut (*data).tuple;
        let datum = libpq::heap_copy_tuple_as_datum(heap_tuple, desc);
        let empty_oid: libpq::Oid = 0;
        let json = libpq::DirectFunctionCall1Coll(Some(row_to_json),
                                                  empty_oid,
                                                  datum);
        let ptr = json as *const libpq::Struct_varlena;
        let text = libpq::text_to_cstring(ptr);
        libpq::appendStringInfoString(out, text);
    } else {
        append("{}", out);
    }
}

unsafe fn append<T: Into<Vec<u8>>>(t: T, out: libpq::StringInfo) {
    libpq::appendStringInfoString(out, CString::new(t).unwrap().as_ptr());
}

unsafe fn append_schema(relation: libpq::Relation, out: libpq::StringInfo) {
    let relid = (*relation).rd_id;
    let form = (*relation).rd_rel;
    let tupdesc = (*relation).rd_att;
    let name = libpq::get_rel_name(relid);
    let ns = libpq::get_namespace_name(libpq::get_rel_namespace(relid));
    let qualified_name = libpq::quote_qualified_identifier(ns, name);
    append("{ \"table\": ", out);
    append("\"", out);
    libpq::appendStringInfoString(out, qualified_name);
    append("\"", out);
    append(", ", out);
    append(" \"schema\": ", out);
    append("[", out);
    let fmt = CString::new("{\"%s\":\"%s\"}").unwrap();
    let mut first: bool = true;
    for i in 0..(*tupdesc).natts {
        let attr = *(*tupdesc).attrs.offset(i as isize);
        let num = (*attr).attnum;
        if (*attr).attisdropped == 1 || num <= 0 {
            continue;
        }
        let col = libpq::get_attname(relid, num);
        let typ = libpq::format_type_be(libpq::get_atttype(relid, num));
        if !first {
            append(",", out);
        } else {
            first = false;
        }
        libpq::appendStringInfo(out, fmt.as_ptr(), col, typ);
    }
    append("]", out);
    append(" }", out);
}

extern fn row_to_json(fcinfo: libpq::FunctionCallInfo) -> libpq::Datum {
    // We wrap the unsafe call to make it safe.
    unsafe {
        libpq::row_to_json(fcinfo)
    }
}

// Symbols Postgres needs to find.

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn _PG_init() { }

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn
    _PG_output_plugin_init(cb: *mut libpq::OutputPluginCallbacks) { init(cb); }
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![deny(warnings)]
// https://github.com/Marwes/combine/issues/172
#![recursion_limit = "256"]

//! # `toml_edit`
//!
//! This crate allows you to parse and modify toml
//! documents, while preserving comments, spaces* and
//! relative order* or items.
//!
//! It is primarily tailored to the needs of [cargo-edit](https://github.com/killercup/cargo-edit/).
//!
//! # Example
//!
//! ```rust
//! use toml_edit::{Document, value};
//!
//! let toml = r#"
//! "hello" = 'toml!' # comment
//! ['a'.b]
//! "#;
//! let mut doc = toml.parse::<Document>().expect("invalid doc");
//! assert_eq!(doc.to_string(), toml);
//! // let's add a new key/value pair inside a.b: c = {d = "hello"}
//! doc["a"]["b"]["c"]["d"] = value("hello");
//! // autoformat inline table a.b.c: { d = "hello" }
//! doc["a"]["b"]["c"].as_inline_table_mut().map(|t| t.fmt());
//! let expected = r#"
//! "hello" = 'toml!' # comment
//! ['a'.b]
//! c = { d = "hello" }
//! "#;
//! assert_eq!(doc.to_string(), expected);
//! ```
//!
//! ## Limitations
//!
//! Things it does not preserve:
//!
//! * Different quotes and spaces around the same table key, e.g.
//!
//! ```text
//! [ 'a'. b]
//! [ "a"  .c]
//! [a.d]
//! ```
//!
//! will be represented as (spaces are removed, the first encountered quote type is used)
//!
//! ```text
//! ['a'.b]
//! ['a'.c]
//! ['a'.d]
//! ```
//!
//! * Children tables before parent table (tables are reordered by default, see [test]).
//! * Scattered array of tables (tables are reordered by default, see [test]).
//!
//! The reason behind the first limitation is that `Table` does not store its header,
//! allowing us to safely swap two tables
//! (we store a mapping in each table: child key -> child table).
//!
//! This last two limitations allow us to represent a toml document as a tree-like data structure,
//! which enables easier implementation of editing operations
//! and an easy to use and type-safe API. If you care about the above two cases,
//! you can use `Document::to_string_in_original_order()` to reconstruct tables in their original order.
//!
//! [test]: https://github.com/ordian/toml_edit/blob/f09bd5d075fdb7d2ef8d9bb3270a34506c276753/tests/test_valid.rs#L84

mod array_of_tables;
mod decor;
mod display;
mod document;
pub(crate) mod formatted;
mod index;
mod key;
mod parser;
mod table;
mod value;

pub use crate::array_of_tables::ArrayOfTables;
pub use crate::document::Document;
pub use crate::key::Key;
pub use crate::parser::TomlError;
pub use crate::table::{array, table, value, Item, Iter, Table, TableLike};
pub use crate::value::{Array, InlineTable, Value};
pub use formatted::decorated;
<commit_msg>export a couple of types as part of the public API<commit_after>#![deny(missing_docs)]
#![deny(warnings)]
// https://github.com/Marwes/combine/issues/172
#![recursion_limit = "256"]

//! # `toml_edit`
//!
//! This crate allows you to parse and modify toml
//! documents, while preserving comments, spaces* and
//! relative order* or items.
//!
//! It is primarily tailored to the needs of [cargo-edit](https://github.com/killercup/cargo-edit/).
//!
//! # Example
//!
//! ```rust
//! use toml_edit::{Document, value};
//!
//! let toml = r#"
//! "hello" = 'toml!' # comment
//! ['a'.b]
//! "#;
//! let mut doc = toml.parse::<Document>().expect("invalid doc");
//! assert_eq!(doc.to_string(), toml);
//! // let's add a new key/value pair inside a.b: c = {d = "hello"}
//! doc["a"]["b"]["c"]["d"] = value("hello");
//! // autoformat inline table a.b.c: { d = "hello" }
//! doc["a"]["b"]["c"].as_inline_table_mut().map(|t| t.fmt());
//! let expected = r#"
//! "hello" = 'toml!' # comment
//! ['a'.b]
//! c = { d = "hello" }
//! "#;
//! assert_eq!(doc.to_string(), expected);
//! ```
//!
//! ## Limitations
//!
//! Things it does not preserve:
//!
//! * Different quotes and spaces around the same table key, e.g.
//!
//! ```text
//! [ 'a'. b]
//! [ "a"  .c]
//! [a.d]
//! ```
//!
//! will be represented as (spaces are removed, the first encountered quote type is used)
//!
//! ```text
//! ['a'.b]
//! ['a'.c]
//! ['a'.d]
//! ```
//!
//! * Children tables before parent table (tables are reordered by default, see [test]).
//! * Scattered array of tables (tables are reordered by default, see [test]).
//!
//! The reason behind the first limitation is that `Table` does not store its header,
//! allowing us to safely swap two tables
//! (we store a mapping in each table: child key -> child table).
//!
//! This last two limitations allow us to represent a toml document as a tree-like data structure,
//! which enables easier implementation of editing operations
//! and an easy to use and type-safe API. If you care about the above two cases,
//! you can use `Document::to_string_in_original_order()` to reconstruct tables in their original order.
//!
//! [test]: https://github.com/ordian/toml_edit/blob/f09bd5d075fdb7d2ef8d9bb3270a34506c276753/tests/test_valid.rs#L84

mod array_of_tables;
mod decor;
mod display;
mod document;
pub(crate) mod formatted;
mod index;
mod key;
mod parser;
mod table;
mod value;

pub use crate::array_of_tables::ArrayOfTables;
pub use crate::document::Document;
pub use crate::decor::Decor;
pub use crate::key::Key;
pub use crate::parser::TomlError;
pub use crate::table::{array, table, value, Item, Iter, Table, TableLike};
pub use crate::value::{Array, ArrayIter, InlineTable, Value};
pub use formatted::decorated;
<|endoftext|>


<commit_before>//! [![github]](https://github.com/dtolnay/serde-yaml) [![crates-io]](https://crates.io/crates/serde-yaml) [![docs-rs]](https://docs.rs/serde-yaml)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
//!
//!

//!
//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: https://yaml.org/
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "x: 1.0\ny: 2.0\n");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "x: 1.0\ny: 2.0\n");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.26")]
#![deny(missing_docs)]
// Suppressed clippy_pedantic lints
#![allow(
    // buggy
    clippy::iter_not_returning_iterator, // https://github.com/rust-lang/rust-clippy/issues/8285
    clippy::question_mark, // https://github.com/rust-lang/rust-clippy/issues/7859
    // private Deserializer::next
    clippy::should_implement_trait,
    // things are often more readable this way
    clippy::cast_lossless,
    clippy::checked_conversions,
    clippy::if_not_else,
    clippy::manual_assert,
    clippy::match_like_matches_macro,
    clippy::match_same_arms,
    clippy::module_name_repetitions,
    clippy::needless_pass_by_value,
    clippy::option_if_let_else,
    clippy::redundant_else,
    clippy::single_match_else,
    // code is acceptable
    clippy::blocks_in_if_conditions,
    clippy::cast_possible_truncation,
    clippy::cast_possible_wrap,
    clippy::cast_precision_loss,
    clippy::cast_sign_loss,
    clippy::derive_partial_eq_without_eq,
    clippy::doc_markdown,
    clippy::items_after_statements,
    clippy::let_underscore_drop,
    clippy::manual_map,
    clippy::never_loop,
    clippy::return_self_not_must_use,
    clippy::unsafe_removed_from_name,
    clippy::wildcard_in_or_patterns,
    // noisy
    clippy::missing_errors_doc,
    clippy::must_use_candidate,
)]

pub use crate::de::{from_reader, from_slice, from_str, Deserializer};
pub use crate::error::{Error, Location, Result};
pub use crate::ser::{to_string, to_vec, to_writer, Serializer};
#[doc(inline)]
pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value};

#[doc(inline)]
pub use crate::mapping::Mapping;

/// Entry points for deserializing with pre-existing state.
///
/// These functions are only exposed this way because we don't yet expose a
/// Deserializer type. Data formats that have a public Deserializer should not
/// copy these signatures.
pub mod seed {
    pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed};
}

mod de;
mod error;
mod libyaml;
mod loader;
pub mod mapping;
mod number;
mod path;
mod ser;
pub mod value;
<commit_msg>Ignore missing_panics_doc pedantic clippy lint<commit_after>//! [![github]](https://github.com/dtolnay/serde-yaml) [![crates-io]](https://crates.io/crates/serde-yaml) [![docs-rs]](https://docs.rs/serde-yaml)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
//!
//!

//!
//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: https://yaml.org/
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "x: 1.0\ny: 2.0\n");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "x: 1.0\ny: 2.0\n");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.26")]
#![deny(missing_docs)]
// Suppressed clippy_pedantic lints
#![allow(
    // buggy
    clippy::iter_not_returning_iterator, // https://github.com/rust-lang/rust-clippy/issues/8285
    clippy::question_mark, // https://github.com/rust-lang/rust-clippy/issues/7859
    // private Deserializer::next
    clippy::should_implement_trait,
    // things are often more readable this way
    clippy::cast_lossless,
    clippy::checked_conversions,
    clippy::if_not_else,
    clippy::manual_assert,
    clippy::match_like_matches_macro,
    clippy::match_same_arms,
    clippy::module_name_repetitions,
    clippy::needless_pass_by_value,
    clippy::option_if_let_else,
    clippy::redundant_else,
    clippy::single_match_else,
    // code is acceptable
    clippy::blocks_in_if_conditions,
    clippy::cast_possible_truncation,
    clippy::cast_possible_wrap,
    clippy::cast_precision_loss,
    clippy::cast_sign_loss,
    clippy::derive_partial_eq_without_eq,
    clippy::doc_markdown,
    clippy::items_after_statements,
    clippy::let_underscore_drop,
    clippy::manual_map,
    clippy::missing_panics_doc,
    clippy::never_loop,
    clippy::return_self_not_must_use,
    clippy::unsafe_removed_from_name,
    clippy::wildcard_in_or_patterns,
    // noisy
    clippy::missing_errors_doc,
    clippy::must_use_candidate,
)]

pub use crate::de::{from_reader, from_slice, from_str, Deserializer};
pub use crate::error::{Error, Location, Result};
pub use crate::ser::{to_string, to_vec, to_writer, Serializer};
#[doc(inline)]
pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value};

#[doc(inline)]
pub use crate::mapping::Mapping;

/// Entry points for deserializing with pre-existing state.
///
/// These functions are only exposed this way because we don't yet expose a
/// Deserializer type. Data formats that have a public Deserializer should not
/// copy these signatures.
pub mod seed {
    pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed};
}

mod de;
mod error;
mod libyaml;
mod loader;
pub mod mapping;
mod number;
mod path;
mod ser;
pub mod value;
<|endoftext|>


<commit_before>//! A build dependency for Cargo libraries to find system artifacts through the
//! `pkg-config` utility.
//!
//! This library will shell out to `pkg-config` as part of build scripts and
//! probe the system to determine how to link to a specified library. The
//! `Config` structure serves as a method of configuring how `pkg-config` is
//! invoked in a builder style.
//!
//! A number of environment variables are available to globally configure how
//! this crate will invoke `pkg-config`:
//!
//! * `PKG_CONFIG_ALLOW_CROSS` - if this variable is not set, then `pkg-config`
//!   will automatically be disabled for all cross compiles.
//! * `FOO_NO_PKG_CONFIG` - if set, this will disable running `pkg-config` when
//!   probing for the library named `foo`.
//!
//! There are also a number of environment variables which can configure how a
//! library is linked to (dynamically vs statically). These variables control
//! whether the `--static` flag is passed. Note that this behavior can be
//! overridden by configuring explicitly on `Config`. The variables are checked
//! in the following order:
//!
//! * `FOO_STATIC` - pass `--static` for the library `foo`
//! * `FOO_DYNAMIC` - do not pass `--static` for the library `foo`
//! * `PKG_CONFIG_ALL_STATIC` - pass `--static` for all libraries
//! * `PKG_CONFIG_ALL_DYNAMIC` - do not pass `--static` for all libraries
//!
//! After running `pkg-config` all appropriate Cargo metadata will be printed on
//! stdout if the search was successful.
//!
//! # Example
//!
//! Find the system library named `foo`.
//!
//! ```no_run
//! extern crate "pkg-config" as pkg_config;
//!
//! fn main() {
//!     pkg_config::find_library("foo").unwrap();
//! }
//! ```
//!
//! Configure how library `foo` is linked to.
//!
//! ```no_run
//! extern crate "pkg-config" as pkg_config;
//!
//! fn main() {
//!     pkg_config::Config::new().statik(true).find("foo").unwrap();
//! }
//! ```

#![doc(html_root_url = "http://alexcrichton.com/pkg-config-rs")]
#![cfg_attr(test, deny(warnings))]

use std::ascii::AsciiExt;
use std::env;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
use std::str;

pub fn target_supported() -> bool {
    env::var("HOST") == env::var("TARGET") ||
        env::var_os("PKG_CONFIG_ALLOW_CROSS").is_some()
}

#[derive(Clone)]
pub struct Config {
    statik: Option<bool>,
    atleast_version: Option<String>,
}

#[derive(Debug)]
pub struct Library {
    pub libs: Vec<String>,
    pub link_paths: Vec<PathBuf>,
    pub frameworks: Vec<String>,
    pub framework_paths: Vec<PathBuf>,
    pub include_paths: Vec<PathBuf>,
    _priv: (),
}

/// Simple shortcut for using all default options for finding a library.
pub fn find_library(name: &str) -> Result<Library, String> {
    Config::new().find(name)
}

impl Config {
    /// Creates a new set of configuration options which are all initially set
    /// to "blank".
    pub fn new() -> Config {
        Config {
            statik: None,
            atleast_version: None,
        }
    }

    /// Indicate whether the `--static` flag should be passed.
    ///
    /// This will override the inference from environment variables described in
    /// the crate documentation.
    pub fn statik(&mut self, statik: bool) -> &mut Config {
        self.statik = Some(statik);
        self
    }

    /// Indicate that the library must be at least version `vers`.
    pub fn atleast_version(&mut self, vers: &str) -> &mut Config {
        self.atleast_version = Some(vers.to_string());
        self
    }

    /// Run `pkg-config` to find the library `name`.
    ///
    /// This will use all configuration previously set to specify how
    /// `pkg-config` is run.
    pub fn find(&self, name: &str) -> Result<Library, String> {
        if env::var_os(&format!("{}_NO_PKG_CONFIG", envify(name))).is_some() {
            return Err(format!("pkg-config requested to be aborted for {}", name))
        } else if !target_supported() {
            return Err("pkg-config doesn't handle cross compilation. Use \
                        PKG_CONFIG_ALLOW_CROSS=1 to override".to_string());
        }

        let mut cmd = Command::new("pkg-config");
        let statik = self.statik.unwrap_or(infer_static(name));
        if statik {
            cmd.arg("--static");
        }
        cmd.arg("--libs").arg("--cflags")
           .env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");
        match self.atleast_version {
            Some(ref v) => { cmd.arg(&format!("{} >= {}", name, v)); }
            None => { cmd.arg(name); }
        }
        let out = try!(cmd.output().map_err(|e| {
            format!("failed to run `{:?}`: {}", cmd, e)
        }));
        let stdout = str::from_utf8(&out.stdout).unwrap();
        let stderr = str::from_utf8(&out.stderr).unwrap();
        if !out.status.success() {
            let mut msg = format!("`{:?}` did not exit successfully: {}", cmd,
                                  out.status);
            if stdout.len() > 0 {
                msg.push_str("\n--- stdout\n");
                msg.push_str(stdout);
            }
            if stderr.len() > 0 {
                msg.push_str("\n--- stderr\n");
                msg.push_str(stderr);
            }
            return Err(msg)
        }

        let mut ret = Library {
            libs: Vec::new(),
            link_paths: Vec::new(),
            include_paths: Vec::new(),
            frameworks: Vec::new(),
            framework_paths: Vec::new(),
            _priv: (),
        };
        let mut dirs = Vec::new();
        let parts = stdout.split(' ').filter(|l| l.len() > 2)
                          .map(|arg| (&arg[0..2], &arg[2..]))
                          .collect::<Vec<_>>();
        for &(flag, val) in parts.iter() {
            if flag == "-L" {
                println!("cargo:rustc-flags=-L native={}", val);
                dirs.push(PathBuf::new(val));
                ret.link_paths.push(PathBuf::new(val));
            } else if flag == "-F" {
                println!("cargo:rustc-flags=-L framework={}", val);
                ret.framework_paths.push(PathBuf::new(val));
            } else if flag == "-I" {
                ret.include_paths.push(PathBuf::new(val));
            }
        }
        for &(flag, val) in parts.iter() {
            if flag == "-l" {
                ret.libs.push(val.to_string());
                if statik && !is_system_lib(val, &dirs) {
                    println!("cargo:rustc-flags=-l static={}", val);
                } else {
                    println!("cargo:rustc-flags=-l {}", val);
                }
            }
        }
        let mut iter = stdout.split(' ');
        while let Some(part) = iter.next() {
            if part != "-framework" { continue }
            if let Some(lib) = iter.next() {
                println!("cargo:rustc-flags=-l framework={}", lib);
                ret.frameworks.push(lib.to_string());
            }
        }

        Ok(ret)
    }
}

fn infer_static(name: &str) -> bool {
    let name = envify(name);
    if env::var_os(&format!("{}_STATIC", name)).is_some() {
        true
    } else if env::var_os(&format!("{}_DYNAMIC", name)).is_some() {
        false
    } else if env::var_os("PKG_CONFIG_ALL_STATIC").is_some() {
        true
    } else if env::var_os("PKG_CONFIG_ALL_DYNAMIC").is_some() {
        false
    } else {
        false
    }
}

fn envify(name: &str) -> String {
    name.chars().map(|c| c.to_ascii_uppercase()).map(|c| if c == '-' {'_'} else {c})
        .collect()
}

fn is_system_lib(name: &str, dirs: &[PathBuf]) -> bool {
    let libname = format!("lib{}.a", name);
    let root = Path::new("/usr");
    !dirs.iter().any(|d| {
        !d.starts_with(root) && fs::metadata(&d.join(&libname)).is_ok()
    })
}
<commit_msg>Use new dedicated metadata of Cargo<commit_after>//! A build dependency for Cargo libraries to find system artifacts through the
//! `pkg-config` utility.
//!
//! This library will shell out to `pkg-config` as part of build scripts and
//! probe the system to determine how to link to a specified library. The
//! `Config` structure serves as a method of configuring how `pkg-config` is
//! invoked in a builder style.
//!
//! A number of environment variables are available to globally configure how
//! this crate will invoke `pkg-config`:
//!
//! * `PKG_CONFIG_ALLOW_CROSS` - if this variable is not set, then `pkg-config`
//!   will automatically be disabled for all cross compiles.
//! * `FOO_NO_PKG_CONFIG` - if set, this will disable running `pkg-config` when
//!   probing for the library named `foo`.
//!
//! There are also a number of environment variables which can configure how a
//! library is linked to (dynamically vs statically). These variables control
//! whether the `--static` flag is passed. Note that this behavior can be
//! overridden by configuring explicitly on `Config`. The variables are checked
//! in the following order:
//!
//! * `FOO_STATIC` - pass `--static` for the library `foo`
//! * `FOO_DYNAMIC` - do not pass `--static` for the library `foo`
//! * `PKG_CONFIG_ALL_STATIC` - pass `--static` for all libraries
//! * `PKG_CONFIG_ALL_DYNAMIC` - do not pass `--static` for all libraries
//!
//! After running `pkg-config` all appropriate Cargo metadata will be printed on
//! stdout if the search was successful.
//!
//! # Example
//!
//! Find the system library named `foo`.
//!
//! ```no_run
//! extern crate "pkg-config" as pkg_config;
//!
//! fn main() {
//!     pkg_config::find_library("foo").unwrap();
//! }
//! ```
//!
//! Configure how library `foo` is linked to.
//!
//! ```no_run
//! extern crate "pkg-config" as pkg_config;
//!
//! fn main() {
//!     pkg_config::Config::new().statik(true).find("foo").unwrap();
//! }
//! ```

#![doc(html_root_url = "http://alexcrichton.com/pkg-config-rs")]
#![cfg_attr(test, deny(warnings))]

use std::ascii::AsciiExt;
use std::env;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
use std::str;

pub fn target_supported() -> bool {
    env::var("HOST") == env::var("TARGET") ||
        env::var_os("PKG_CONFIG_ALLOW_CROSS").is_some()
}

#[derive(Clone)]
pub struct Config {
    statik: Option<bool>,
    atleast_version: Option<String>,
}

#[derive(Debug)]
pub struct Library {
    pub libs: Vec<String>,
    pub link_paths: Vec<PathBuf>,
    pub frameworks: Vec<String>,
    pub framework_paths: Vec<PathBuf>,
    pub include_paths: Vec<PathBuf>,
    _priv: (),
}

/// Simple shortcut for using all default options for finding a library.
pub fn find_library(name: &str) -> Result<Library, String> {
    Config::new().find(name)
}

impl Config {
    /// Creates a new set of configuration options which are all initially set
    /// to "blank".
    pub fn new() -> Config {
        Config {
            statik: None,
            atleast_version: None,
        }
    }

    /// Indicate whether the `--static` flag should be passed.
    ///
    /// This will override the inference from environment variables described in
    /// the crate documentation.
    pub fn statik(&mut self, statik: bool) -> &mut Config {
        self.statik = Some(statik);
        self
    }

    /// Indicate that the library must be at least version `vers`.
    pub fn atleast_version(&mut self, vers: &str) -> &mut Config {
        self.atleast_version = Some(vers.to_string());
        self
    }

    /// Run `pkg-config` to find the library `name`.
    ///
    /// This will use all configuration previously set to specify how
    /// `pkg-config` is run.
    pub fn find(&self, name: &str) -> Result<Library, String> {
        if env::var_os(&format!("{}_NO_PKG_CONFIG", envify(name))).is_some() {
            return Err(format!("pkg-config requested to be aborted for {}", name))
        } else if !target_supported() {
            return Err("pkg-config doesn't handle cross compilation. Use \
                        PKG_CONFIG_ALLOW_CROSS=1 to override".to_string());
        }

        let mut cmd = Command::new("pkg-config");
        let statik = self.statik.unwrap_or(infer_static(name));
        if statik {
            cmd.arg("--static");
        }
        cmd.arg("--libs").arg("--cflags")
           .env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");
        match self.atleast_version {
            Some(ref v) => { cmd.arg(&format!("{} >= {}", name, v)); }
            None => { cmd.arg(name); }
        }
        let out = try!(cmd.output().map_err(|e| {
            format!("failed to run `{:?}`: {}", cmd, e)
        }));
        let stdout = str::from_utf8(&out.stdout).unwrap();
        let stderr = str::from_utf8(&out.stderr).unwrap();
        if !out.status.success() {
            let mut msg = format!("`{:?}` did not exit successfully: {}", cmd,
                                  out.status);
            if stdout.len() > 0 {
                msg.push_str("\n--- stdout\n");
                msg.push_str(stdout);
            }
            if stderr.len() > 0 {
                msg.push_str("\n--- stderr\n");
                msg.push_str(stderr);
            }
            return Err(msg)
        }

        let mut ret = Library {
            libs: Vec::new(),
            link_paths: Vec::new(),
            include_paths: Vec::new(),
            frameworks: Vec::new(),
            framework_paths: Vec::new(),
            _priv: (),
        };
        let mut dirs = Vec::new();
        let parts = stdout.split(' ').filter(|l| l.len() > 2)
                          .map(|arg| (&arg[0..2], &arg[2..]))
                          .collect::<Vec<_>>();
        for &(flag, val) in parts.iter() {
            if flag == "-L" {
                println!("cargo:rustc-link-search=native={}", val);
                dirs.push(PathBuf::new(val));
                ret.link_paths.push(PathBuf::new(val));
            } else if flag == "-F" {
                println!("cargo:rustc-link-search=framework={}", val);
                ret.framework_paths.push(PathBuf::new(val));
            } else if flag == "-I" {
                ret.include_paths.push(PathBuf::new(val));
            }
        }
        for &(flag, val) in parts.iter() {
            if flag == "-l" {
                ret.libs.push(val.to_string());
                if statik && !is_system_lib(val, &dirs) {
                    println!("cargo:rustc-link-lib=static={}", val);
                } else {
                    println!("cargo:rustc-link-lib={}", val);
                }
            }
        }
        let mut iter = stdout.split(' ');
        while let Some(part) = iter.next() {
            if part != "-framework" { continue }
            if let Some(lib) = iter.next() {
                println!("cargo:rustc-link-lib=framework={}", lib);
                ret.frameworks.push(lib.to_string());
            }
        }

        Ok(ret)
    }
}

fn infer_static(name: &str) -> bool {
    let name = envify(name);
    if env::var_os(&format!("{}_STATIC", name)).is_some() {
        true
    } else if env::var_os(&format!("{}_DYNAMIC", name)).is_some() {
        false
    } else if env::var_os("PKG_CONFIG_ALL_STATIC").is_some() {
        true
    } else if env::var_os("PKG_CONFIG_ALL_DYNAMIC").is_some() {
        false
    } else {
        false
    }
}

fn envify(name: &str) -> String {
    name.chars().map(|c| c.to_ascii_uppercase()).map(|c| if c == '-' {'_'} else {c})
        .collect()
}

fn is_system_lib(name: &str, dirs: &[PathBuf]) -> bool {
    let libname = format!("lib{}.a", name);
    let root = Path::new("/usr");
    !dirs.iter().any(|d| {
        !d.starts_with(root) && fs::metadata(&d.join(&libname)).is_ok()
    })
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"]
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate chrono;
extern crate reqwest;
extern crate select;
extern crate rustc_serialize;
#[macro_use] extern crate error_chain;
pub mod extract_date;
pub mod errors;
<commit_msg>Make errors mod private<commit_after>#![recursion_limit = "1024"]
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate chrono;
extern crate reqwest;
extern crate select;
extern crate rustc_serialize;
#[macro_use] extern crate error_chain;
pub mod extract_date;
mod errors;
<|endoftext|>


<commit_before>extern crate libc;
extern crate energymon_sys;
extern crate energymon_default_sys;

use libc::{c_int, c_ulonglong, c_char};
use std::mem;
use std::ptr;
use energymon_sys::*;
use energymon_default_sys::em_impl_get;

/// A basic energy monitor.
pub struct EnergyMon {
    /// The native C struct.
    em: em_impl,
}

impl EnergyMon {
    /// Create and initialize an `EnergyMon`.
    pub fn new() -> Result<EnergyMon, &'static str> {
    	unsafe {
            let mut em: em_impl = mem::uninitialized();
            match em_impl_get(&mut em) {
                0 => (),
                _ => return Err("Failed to create em_impl"),
            }
            match (em.finit)(&mut em) {
            	0 => Ok(EnergyMon{ em: em }),
            	_ => Err("Failed to initialize em_impl"),
        	}
        }
    }

    /// Read the total energy from the `EnergyMon`.
    pub fn read(&self) -> u64 {
        (self.em.fread)(&self.em)
    }

    /// Get a human-readable name of the `EnergyMon`'s source.
    pub fn source(&mut self) -> String {
        const BUFSIZE: usize = 100;
        let mut buf: [c_char; BUFSIZE] = [0; BUFSIZE];
        let ret: *mut c_char = (self.em.fsource)(buf.as_mut_ptr());
        if ret.is_null() {
            return "UNKNOWN".to_owned();
        }
        let buf: &[u8] = unsafe {
            mem::transmute::<&[c_char], &[u8]>(&buf)
        };
        String::from_utf8_lossy(buf).into_owned()
    }

    /// Get the refresh interval for the `EnergyMon`.
    pub fn interval(&self) -> u64 {
        (self.em.finterval)(&self.em)
    }

    /// Cleanup the `EnergyMon`.
    fn finish(&mut self) -> i32 {
    	(self.em.ffinish)(&mut self.em)
    }
}

impl Drop for EnergyMon {
    fn drop(&mut self) {
        self.finish();
    }
}

impl Default for EnergyMon {
    /// Returns a dummy `EnergyMon`.
    fn default() -> EnergyMon {
        extern fn default_init(_impl: *mut em_impl) -> c_int { 0 };
        extern fn default_read_total(_impl: *const em_impl) -> c_ulonglong { 0 };
        extern fn default_finish(_impl: *mut em_impl) -> c_int { 0 };
        extern fn default_get_source(_impl: *mut c_char) -> *mut c_char { ptr::null_mut() };
        extern fn default_get_interval(_impl: *const em_impl) -> c_ulonglong { 1 };
        EnergyMon {
            em: em_impl {
                finit: default_init,
                fread: default_read_total,
                ffinish: default_finish,
                fsource: default_get_source,
                finterval:default_get_interval,
                state: ptr::null_mut(),
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::EnergyMon;

    #[test]
    fn test_interface() {
        let mut em: EnergyMon = EnergyMon::new().unwrap();
        let val = em.read();
        println!("Read {} from {} with refresh interval {}", val, em.source(), em.interval());
    }

    #[test]
    fn test_default() {
        let mut em: EnergyMon = Default::default();
        assert!(em.read() == 0);
        assert!(em.interval() == 1);
        assert!(em.finish() == 0);
        assert!(em.source().eq("UNKNOWN"));
        assert!(em.em.state.is_null())
    }

}
<commit_msg>Name refactoring in native lib<commit_after>extern crate libc;
extern crate energymon_sys;
extern crate energymon_default_sys;

use libc::{c_int, c_ulonglong, c_char};
use std::mem;
use std::ptr;
use energymon_sys::*;
use energymon_default_sys::energymon_get_default;

/// A basic energy monitor.
pub struct EnergyMon {
    /// The native C struct.
    em: energymon,
}

impl EnergyMon {
    /// Create and initialize an `EnergyMon`.
    pub fn new() -> Result<EnergyMon, &'static str> {
    	unsafe {
            let mut em: energymon = mem::uninitialized();
            match energymon_get_default(&mut em) {
                0 => (),
                _ => return Err("Failed to create energymon"),
            }
            match (em.finit)(&mut em) {
            	0 => Ok(EnergyMon{ em: em }),
            	_ => Err("Failed to initialize energymon"),
        	}
        }
    }

    /// Read the total energy from the `EnergyMon`.
    pub fn read(&self) -> u64 {
        (self.em.fread)(&self.em)
    }

    /// Get a human-readable name of the `EnergyMon`'s source.
    pub fn source(&mut self) -> String {
        const BUFSIZE: usize = 100;
        let mut buf: [c_char; BUFSIZE] = [0; BUFSIZE];
        let ret: *mut c_char = (self.em.fsource)(buf.as_mut_ptr());
        if ret.is_null() {
            return "UNKNOWN".to_owned();
        }
        let buf: &[u8] = unsafe {
            mem::transmute::<&[c_char], &[u8]>(&buf)
        };
        String::from_utf8_lossy(buf).into_owned()
    }

    /// Get the refresh interval for the `EnergyMon`.
    pub fn interval(&self) -> u64 {
        (self.em.finterval)(&self.em)
    }

    /// Cleanup the `EnergyMon`.
    fn finish(&mut self) -> i32 {
    	(self.em.ffinish)(&mut self.em)
    }
}

impl Drop for EnergyMon {
    fn drop(&mut self) {
        self.finish();
    }
}

impl Default for EnergyMon {
    /// Returns a dummy `EnergyMon`.
    fn default() -> EnergyMon {
        extern fn default_init(_impl: *mut energymon) -> c_int { 0 };
        extern fn default_read_total(_impl: *const energymon) -> c_ulonglong { 0 };
        extern fn default_finish(_impl: *mut energymon) -> c_int { 0 };
        extern fn default_get_source(_impl: *mut c_char) -> *mut c_char { ptr::null_mut() };
        extern fn default_get_interval(_impl: *const energymon) -> c_ulonglong { 1 };
        EnergyMon {
            em: energymon {
                finit: default_init,
                fread: default_read_total,
                ffinish: default_finish,
                fsource: default_get_source,
                finterval:default_get_interval,
                state: ptr::null_mut(),
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::EnergyMon;

    #[test]
    fn test_interface() {
        let mut em: EnergyMon = EnergyMon::new().unwrap();
        let val = em.read();
        println!("Read {} from {} with refresh interval {}", val, em.source(), em.interval());
    }

    #[test]
    fn test_default() {
        let mut em: EnergyMon = Default::default();
        assert!(em.read() == 0);
        assert!(em.interval() == 1);
        assert!(em.finish() == 0);
        assert!(em.source().eq("UNKNOWN"));
        assert!(em.em.state.is_null())
    }

}
<|endoftext|>