<commit_before>extern crate discord;
extern crate dotenv;
#[macro_use]
extern crate serde_derive;
extern crate envy;

use discord::{Discord, State};
use discord::model::{Event};
use discord::voice::AudioSource;

use std::collections::HashMap;
use std::sync::mpsc::{channel, Sender, Receiver};

#[derive(Default)]
struct Dj {
  controls: HashMap<u64, Sender<AudioSourceControl>>
}

pub enum MusicItem {
  YouTube(String)
}

fn main() {
  println!("Loading .env");

  dotenv::dotenv().ok();

  println!("Reading environment variables");

  let environment: Environment = envy::from_env().expect("Invalid or missing environment variables");

  println!("Creating bot");

  let discord = Discord::from_bot_token(&environment.discord_bot_token).expect("could not start discord from bot token");
  let (mut connection, ready) = discord.connect().expect("could not connect");
  let mut state = State::new(ready);

  let mut dj = Dj::default();

  loop {
    let event = match connection.recv_event() {
      Ok(e) => e,
      Err(e) => {
        println!("could not receive event: {}", e);
        continue;
      }
    };

    state.update(&event);

    let valid_commands = &["!play", "!stop", "!clear", "!pause", "!resume"];

    match event {
      Event::MessageCreate(message) => {
        let params: Vec<&str> = message.content.split_whitespace().collect();
        if params.is_empty() || params[0].len() < 2 {
          continue;
        }

        let command: String = params[0].to_lowercase().chars().skip(1).collect();
        if !valid_commands.contains(&command.as_ref()) {
          continue;
        }

        let (server_id, voice_channel) = match state.find_voice_user(message.author.id) {
          Some((Some(server_id), voice_channel)) => (server_id, voice_channel),
          _ => {
            if let Err(e) = discord.send_embed(message.channel_id, "", |e| e.description("Must be in a public voice channel to DJ.")) {
              println!("could not send message: {}", e);
            }
            continue;
          }
        };

        let voice = connection.voice(Some(server_id));

        match command.as_ref() {
          "play" => {
            if params.len() < 2 {
              if let Err(e) = discord.send_embed(message.channel_id, "", |e| e.description("Please provide a YouTube URL to play.")) {
                println!("could not send message: {}", e);
              }
              continue;
            }
            let url = params[1];
            if let Some((_, controls)) = dj.controls.iter().find(|&(id, _)| *id == voice_channel.0) {
              if let Err(e) = controls.send(AudioSourceControl::AddQueue(url.to_string())) {
                println!("could not send control: {}", e);
              }
              continue;
            }
            let source = match discord::voice::open_ytdl_stream(url) {
              Ok(s) => s,
              Err(e) => {
                println!("could not open source: {}", e);
                if let Err(e) = discord.send_embed(message.channel_id, "", |e| e.description("Could not open video for streaming.")) {
                  println!("could not send message: {}", e);
                }
                continue;
              }
            };

            voice.connect(voice_channel);

            let (tx, rx) = channel();
            dj.controls.insert(voice_channel.0, tx);
            let buf_source = BufferedQueuedAudioSource::new(source, rx);
            voice.play(Box::new(buf_source));
          },
          "stop" => {
            let control = match dj.controls.get(&voice_channel.0) {
              Some(c) => c,
              None => continue
            };
            if let Err(e) = control.send(AudioSourceControl::Stop) {
              println!("couldn't send control: {}", e);
            }
          },
          "pause" => {
            let control = match dj.controls.get(&voice_channel.0) {
              Some(c) => c,
              None => continue
            };
            if let Err(e) = control.send(AudioSourceControl::Pause) {
              println!("couldn't send control: {}", e);
            }
          },
          "resume" => {
            let control = match dj.controls.get(&voice_channel.0) {
              Some(c) => c,
              None => continue
            };
            if let Err(e) = control.send(AudioSourceControl::Resume) {
              println!("couldn't send control: {}", e);
            }
          },
          "clear" => {
            let control = match dj.controls.get(&voice_channel.0) {
              Some(c) => c,
              None => continue
            };
            if let Err(e) = control.send(AudioSourceControl::ClearQueue) {
              println!("couldn't send control: {}", e);
            }
          },
          _ => continue
        }
      },
      Event::VoiceStateUpdate(server_id, _) => {
        let chan = match connection.voice(server_id).current_channel() {
          Some(c) => c,
          None => continue
        };
        if let Some(server_id) = server_id {
          if let Some(srv) = state.servers().iter().find(|srv| srv.id == server_id) {
            if srv.voice_states.iter().filter(|vs| vs.channel_id == Some(chan)).count() <= 1 {
              connection.voice(Some(server_id)).disconnect();
            }
          }
        }
      },
      _ => {}
    }
  }
}

#[derive(Debug, Deserialize)]
pub struct Environment {
  #[serde(rename = "lb_discord_bot_token")]
  pub discord_bot_token: String,
}

pub enum AudioSourceControl {
  Pause,
  Resume,
  Stop,
  AddQueue(String),
  ClearQueue
}

struct BufferedQueuedAudioSource {
  controls: Receiver<AudioSourceControl>,
  source: Box<AudioSource>,
  buffer: Box<[i16]>,
  queue: Vec<String>,
  position: usize,
  capacity: usize,
  paused: bool,
  finished: bool
}

impl BufferedQueuedAudioSource {
  fn new(source: Box<AudioSource>, controls: Receiver<AudioSourceControl>) -> Self {
    BufferedQueuedAudioSource {
      controls: controls,
      source: source,
      buffer: vec![0; 61440].into_boxed_slice(),
      queue: Vec::default(),
      position: 0,
      capacity: 0,
      paused: false,
      finished: false
    }
  }
}

impl AudioSource for BufferedQueuedAudioSource {
  fn is_stereo(&mut self) -> bool {
    self.source.is_stereo()
  }

  fn read_frame(&mut self, buffer: &mut [i16]) -> Option<usize> {
    self.read_controls();
    self.handle_queue();
    if self.paused {
      for byte in buffer.iter_mut() {
        *byte = 0;
      }
      return Some(buffer.len());
    }
    self.read(buffer)
  }
}

impl BufferedQueuedAudioSource {
  fn read_controls(&mut self) {
    while let Ok(control) = self.controls.try_recv() {
      match control {
        AudioSourceControl::Resume => self.paused = false,
        AudioSourceControl::Pause => self.paused = true,
        AudioSourceControl::AddQueue(s) => self.queue.push(s),
        AudioSourceControl::ClearQueue => self.queue.clear(),
        AudioSourceControl::Stop => {
          self.queue.clear();
          self.finished = true;
        }
      }
    }
  }

  fn handle_queue(&mut self) {
    if !self.finished || self.queue.is_empty() {
      return;
    }
    while !self.queue.is_empty() {
      let first = self.queue.remove(0);
      match discord::voice::open_ytdl_stream(&first) {
        Ok(s) => {
          self.source = s;
          self.finished = false;
          break;
        },
        Err(e) => {
          println!("could not open ytdl stream in queue: {}", e);
          continue;
        }
      }
    }
  }

  fn read(&mut self, buffer: &mut [i16]) -> Option<usize> {
    if self.position == self.capacity && buffer.len() >= self.buffer.len() {
      return self.source.read_frame(buffer);
    }
    let nread = {
      let rem = match self.fill_buff() {
        Some(s) => s,
        None => return None
      };
      let read = std::cmp::min(buffer.len(), rem.len());
      for i in 0..read {
        buffer[i] = rem[i];
      }
      read
    };
    self.consume(nread);
    Some(nread)
  }

  fn fill_buff(&mut self) -> Option<&[i16]> {
    if self.position >= self.capacity {
      self.capacity = match self.source.read_frame(&mut self.buffer) {
        Some(s) => s,
        None => return None
      };
      // FIXME: This should happen when read_frame turns None, but discord-rs has a bug
      // https://github.com/SpaceManiac/discord-rs/issues/107
      if self.capacity == 0 && !self.finished {
        self.finished = true;
      }
      self.position = 0;
    }
    Some(&self.buffer[self.position..self.capacity])
  }

  fn consume(&mut self, amt: usize) {
    self.position = std::cmp::min(self.position + amt, self.capacity);
  }
}
<commit_msg>fix: don't include !<commit_after>extern crate discord;
extern crate dotenv;
#[macro_use]
extern crate serde_derive;
extern crate envy;

use discord::{Discord, State};
use discord::model::{Event};
use discord::voice::AudioSource;

use std::collections::HashMap;
use std::sync::mpsc::{channel, Sender, Receiver};

#[derive(Default)]
struct Dj {
  controls: HashMap<u64, Sender<AudioSourceControl>>
}

pub enum MusicItem {
  YouTube(String)
}

fn main() {
  println!("Loading .env");

  dotenv::dotenv().ok();

  println!("Reading environment variables");

  let environment: Environment = envy::from_env().expect("Invalid or missing environment variables");

  println!("Creating bot");

  let discord = Discord::from_bot_token(&environment.discord_bot_token).expect("could not start discord from bot token");
  let (mut connection, ready) = discord.connect().expect("could not connect");
  let mut state = State::new(ready);

  let mut dj = Dj::default();

  loop {
    let event = match connection.recv_event() {
      Ok(e) => e,
      Err(e) => {
        println!("could not receive event: {}", e);
        continue;
      }
    };

    state.update(&event);

    let valid_commands = &["play", "stop", "clear", "pause", "resume"];

    match event {
      Event::MessageCreate(message) => {
        let params: Vec<&str> = message.content.split_whitespace().collect();
        if params.is_empty() || params[0].len() < 2 {
          continue;
        }

        let command: String = params[0].to_lowercase().chars().skip(1).collect();
        if !valid_commands.contains(&command.as_ref()) {
          continue;
        }

        let (server_id, voice_channel) = match state.find_voice_user(message.author.id) {
          Some((Some(server_id), voice_channel)) => (server_id, voice_channel),
          _ => {
            if let Err(e) = discord.send_embed(message.channel_id, "", |e| e.description("Must be in a public voice channel to DJ.")) {
              println!("could not send message: {}", e);
            }
            continue;
          }
        };

        let voice = connection.voice(Some(server_id));

        match command.as_ref() {
          "play" => {
            if params.len() < 2 {
              if let Err(e) = discord.send_embed(message.channel_id, "", |e| e.description("Please provide a YouTube URL to play.")) {
                println!("could not send message: {}", e);
              }
              continue;
            }
            let url = params[1];
            if let Some((_, controls)) = dj.controls.iter().find(|&(id, _)| *id == voice_channel.0) {
              if let Err(e) = controls.send(AudioSourceControl::AddQueue(url.to_string())) {
                println!("could not send control: {}", e);
              }
              continue;
            }
            let source = match discord::voice::open_ytdl_stream(url) {
              Ok(s) => s,
              Err(e) => {
                println!("could not open source: {}", e);
                if let Err(e) = discord.send_embed(message.channel_id, "", |e| e.description("Could not open video for streaming.")) {
                  println!("could not send message: {}", e);
                }
                continue;
              }
            };

            voice.connect(voice_channel);

            let (tx, rx) = channel();
            dj.controls.insert(voice_channel.0, tx);
            let buf_source = BufferedQueuedAudioSource::new(source, rx);
            voice.play(Box::new(buf_source));
          },
          "stop" => {
            let control = match dj.controls.get(&voice_channel.0) {
              Some(c) => c,
              None => continue
            };
            if let Err(e) = control.send(AudioSourceControl::Stop) {
              println!("couldn't send control: {}", e);
            }
          },
          "pause" => {
            let control = match dj.controls.get(&voice_channel.0) {
              Some(c) => c,
              None => continue
            };
            if let Err(e) = control.send(AudioSourceControl::Pause) {
              println!("couldn't send control: {}", e);
            }
          },
          "resume" => {
            let control = match dj.controls.get(&voice_channel.0) {
              Some(c) => c,
              None => continue
            };
            if let Err(e) = control.send(AudioSourceControl::Resume) {
              println!("couldn't send control: {}", e);
            }
          },
          "clear" => {
            let control = match dj.controls.get(&voice_channel.0) {
              Some(c) => c,
              None => continue
            };
            if let Err(e) = control.send(AudioSourceControl::ClearQueue) {
              println!("couldn't send control: {}", e);
            }
          },
          _ => continue
        }
      },
      Event::VoiceStateUpdate(server_id, _) => {
        let chan = match connection.voice(server_id).current_channel() {
          Some(c) => c,
          None => continue
        };
        if let Some(server_id) = server_id {
          if let Some(srv) = state.servers().iter().find(|srv| srv.id == server_id) {
            if srv.voice_states.iter().filter(|vs| vs.channel_id == Some(chan)).count() <= 1 {
              connection.voice(Some(server_id)).disconnect();
            }
          }
        }
      },
      _ => {}
    }
  }
}

#[derive(Debug, Deserialize)]
pub struct Environment {
  #[serde(rename = "lb_discord_bot_token")]
  pub discord_bot_token: String,
}

pub enum AudioSourceControl {
  Pause,
  Resume,
  Stop,
  AddQueue(String),
  ClearQueue
}

struct BufferedQueuedAudioSource {
  controls: Receiver<AudioSourceControl>,
  source: Box<AudioSource>,
  buffer: Box<[i16]>,
  queue: Vec<String>,
  position: usize,
  capacity: usize,
  paused: bool,
  finished: bool
}

impl BufferedQueuedAudioSource {
  fn new(source: Box<AudioSource>, controls: Receiver<AudioSourceControl>) -> Self {
    BufferedQueuedAudioSource {
      controls: controls,
      source: source,
      buffer: vec![0; 61440].into_boxed_slice(),
      queue: Vec::default(),
      position: 0,
      capacity: 0,
      paused: false,
      finished: false
    }
  }
}

impl AudioSource for BufferedQueuedAudioSource {
  fn is_stereo(&mut self) -> bool {
    self.source.is_stereo()
  }

  fn read_frame(&mut self, buffer: &mut [i16]) -> Option<usize> {
    self.read_controls();
    self.handle_queue();
    if self.paused {
      for byte in buffer.iter_mut() {
        *byte = 0;
      }
      return Some(buffer.len());
    }
    self.read(buffer)
  }
}

impl BufferedQueuedAudioSource {
  fn read_controls(&mut self) {
    while let Ok(control) = self.controls.try_recv() {
      match control {
        AudioSourceControl::Resume => self.paused = false,
        AudioSourceControl::Pause => self.paused = true,
        AudioSourceControl::AddQueue(s) => self.queue.push(s),
        AudioSourceControl::ClearQueue => self.queue.clear(),
        AudioSourceControl::Stop => {
          self.queue.clear();
          self.finished = true;
        }
      }
    }
  }

  fn handle_queue(&mut self) {
    if !self.finished || self.queue.is_empty() {
      return;
    }
    while !self.queue.is_empty() {
      let first = self.queue.remove(0);
      match discord::voice::open_ytdl_stream(&first) {
        Ok(s) => {
          self.source = s;
          self.finished = false;
          break;
        },
        Err(e) => {
          println!("could not open ytdl stream in queue: {}", e);
          continue;
        }
      }
    }
  }

  fn read(&mut self, buffer: &mut [i16]) -> Option<usize> {
    if self.position == self.capacity && buffer.len() >= self.buffer.len() {
      return self.source.read_frame(buffer);
    }
    let nread = {
      let rem = match self.fill_buff() {
        Some(s) => s,
        None => return None
      };
      let read = std::cmp::min(buffer.len(), rem.len());
      for i in 0..read {
        buffer[i] = rem[i];
      }
      read
    };
    self.consume(nread);
    Some(nread)
  }

  fn fill_buff(&mut self) -> Option<&[i16]> {
    if self.position >= self.capacity {
      self.capacity = match self.source.read_frame(&mut self.buffer) {
        Some(s) => s,
        None => return None
      };
      // FIXME: This should happen when read_frame turns None, but discord-rs has a bug
      // https://github.com/SpaceManiac/discord-rs/issues/107
      if self.capacity == 0 && !self.finished {
        self.finished = true;
      }
      self.position = 0;
    }
    Some(&self.buffer[self.position..self.capacity])
  }

  fn consume(&mut self, amt: usize) {
    self.position = std::cmp::min(self.position + amt, self.capacity);
  }
}
<|endoftext|>


<commit_before>#[crate_id = "redis-example#0.1"];
#[crate_type = "bin"];

extern mod redis;

fn main() {
    let client = redis::Client::open("redis://127.0.0.1/").unwrap();

    // for fun do it in a task
    do spawn {
        let mut con = client.get_connection().unwrap();
        con.set("foo", 42);
        con.set("bar", "test");
        println!("foo get: {:?}", con.get("foo"));
        println!("foo as int: {:?}", con.get_as::<int>("foo"));
        println!("ping: {:?}", con.ping());
        println!("keys: {:?}", con.keys("*"));
        println!("foo type: {:?}", con.get_type("foo"));
        println!("foo exists: {:?}", con.exists("foo"));

        let info = con.info();
        println!("info role: {:?}", info.find(&~"role"));
        println!("info version: {:?}", info.find(&~"redis_version"));

        let script = redis::Script::new("
            return tonumber(ARGV[1]);
        ");
        println!("script result: {:?}", con.call_script(
            &script, [], [redis::StrArg("42")]));

        println!("last save: {}", con.lastsave().rfc822());
        println!("server time: {}", con.time().rfc822());

        println!("Waiting for item: {:?}", con.blpop(["foox"], 5.0));
    }

    // second task that puts an item into a list
    do spawn {
        let mut con = client.get_connection().unwrap();
        con.rpush("foox", "hello");
    }
}
<commit_msg>Added sleep example<commit_after>#[crate_id = "redis-example#0.1"];
#[crate_type = "bin"];

extern mod redis;

use std::io::timer::sleep;

fn main() {
    let client = redis::Client::open("redis://127.0.0.1/").unwrap();

    // for fun do it in a task
    do spawn {
        let mut con = client.get_connection().unwrap();
        con.set("foo", 42);
        con.set("bar", "test");
        println!("foo get: {:?}", con.get("foo"));
        println!("foo as int: {:?}", con.get_as::<int>("foo"));
        println!("ping: {:?}", con.ping());
        println!("keys: {:?}", con.keys("*"));
        println!("foo type: {:?}", con.get_type("foo"));
        println!("foo exists: {:?}", con.exists("foo"));

        let info = con.info();
        println!("info role: {:?}", info.find(&~"role"));
        println!("info version: {:?}", info.find(&~"redis_version"));

        let script = redis::Script::new("
            return tonumber(ARGV[1]);
        ");
        println!("script result: {:?}", con.call_script(
            &script, [], [redis::StrArg("42")]));

        println!("last save: {}", con.lastsave().rfc822());
        println!("server time: {}", con.time().rfc822());

        println!("Waiting for item: {:?}", con.blpop(["foox"], 5.0));
    }

    // second task that puts an item into a list
    do spawn {
        let mut con = client.get_connection().unwrap();
        println!("Pushing an item in 1 sec");
        sleep(1000);
        con.rpush("foox", "hello");
        println!("Pushed");
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package finding.", why),
    });
}

#[derive(Serialize, Deserialize)]
struct Package {
    name: String,
    version: String,
    crc32: String,
    url: String,
    dependencies: Vec<Package>
}

#[derive(Serialize, Deserialize)]
struct PackageList {
    packages: Vec<Package>,
    last_updated: Date
}

pub fn update_package(url: &str, path: &Path) -> bool {
    download::download_file(url + "packages.json", path);
}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, &str> {
    let mut list = custom_try!(File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = reader.read_to_string();
    let package_list: PackageList = custom_try!(serde_json::from_str(buffer));

    let filtered = package_list.packages.into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err("Package not found"),
        _ => Ok(filtered)
    }
}

<commit_msg>Follow code style.<commit_after>use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package finding.", why),
    });
}

#[derive(Serialize, Deserialize)]
struct Package {
    name: String,
    version: String,
    crc32: String,
    url: String,
    dependencies: Vec<Package>
}

#[derive(Serialize, Deserialize)]
struct PackageList {
    packages: Vec<Package>,
    last_updated: Date
}

pub fn update_package(url: &str, path: &Path) -> bool {
    download::download_file(url + "packages.json", path);
}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, &str> {
    let mut list = custom_try!(File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = reader.read_to_string();
    let package_list: PackageList = custom_try!(serde_json::from_str(buffer));

    let filtered = package_list.packages
                    .into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err("Package not found"),
        _ => Ok(filtered)
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::mem;

use serde_xml;

use credentials::Credentials;
use command::Command;
use region::Region;
use request::{Request, Headers, Query};
use serde_types::{ListBucketResult, BucketLocationResult};
use error::S3Result;

/// # Example
/// ```
/// # // Fake  credentials so we don't access user's real credentials in tests
/// # use std::env;
/// # env::set_var("AWS_ACCESS_KEY_ID", "AKIAIOSFODNN7EXAMPLE");
/// # env::set_var("AWS_SECRET_ACCESS_KEY", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
/// use s3::bucket::Bucket;
/// use s3::credentials::Credentials;
///
/// let bucket_name = "rust-s3-test";
/// let region = "us-east-1".parse().unwrap();
/// let credentials = Credentials::default();
///
/// let bucket = Bucket::new(bucket_name, region, credentials);
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Bucket {
    pub name: String,
    pub region: Region,
    pub credentials: Credentials,
    pub extra_headers: Headers,
    pub extra_query: Query,
}

impl Bucket {
    /// Instantiate a new `Bucket`.
    ///
    /// # Example
    /// ```
    /// # // Fake  credentials so we don't access user's real credentials in tests
    /// # use std::env;
    /// # env::set_var("AWS_ACCESS_KEY_ID", "AKIAIOSFODNN7EXAMPLE");
    /// # env::set_var("AWS_SECRET_ACCESS_KEY", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = "rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    ///
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    /// ```
    pub fn new(name: &str, region: Region, credentials: Credentials) -> S3Result<Bucket> {
        Ok(Bucket {
            name: name.into(),
            region,
            credentials,
            extra_headers: HashMap::new(),
            extra_query: HashMap::new(),
        })
    }

    /// Gets file from an S3 path.
    ///
    /// # Example:
    ///
    /// ```rust,no_run
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = "rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let (data, code) = bucket.get("/test.file").unwrap();
    /// println!("Code: {}\nData: {:?}", code, data);
    /// ```
    pub fn get(&self, path: &str) -> S3Result<(Vec<u8>, u32)> {
        let command = Command::Get;
        let request = Request::new(self, path, command);
        request.execute()
    }

//// Get bucket location from S3
////
/// # Example
/// ```rust,no_run
/// # // Fake  credentials so we don't access user's real credentials in tests
/// # use std::env;
/// # env::set_var("AWS_ACCESS_KEY_ID", "AKIAIOSFODNN7EXAMPLE");
/// # env::set_var("AWS_SECRET_ACCESS_KEY", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
/// use s3::bucket::Bucket;
/// use s3::credentials::Credentials;
///
/// let bucket_name = "rust-s3-test";
/// let region = "eu-central-1".parse().unwrap();
/// let credentials = Credentials::default();
///
/// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
/// println!("{}", bucket.location().unwrap().0)
/// ```
    pub fn location(&self) -> S3Result<(Region, u32)> {
        let request = Request::new(self, "?location", Command::BucketOpGet);
        let result = request.execute()?;
        let result_string = String::from_utf8_lossy(&result.0);
        let region = match serde_xml::deserialize(result_string.as_bytes()) {
            Ok(r) => {
                let location_result: BucketLocationResult = r;
                location_result.region.parse()?
            }
            Err(e) => {
                if e.to_string() == "missing field `$value`" {
                    "us-east-1".parse()?
                } else {
                    bail!(e)
                }
            }
        };
        Ok((region, result.1))
    }

    /// Delete file from an S3 path.
    ///
    /// # Example:
    ///
    /// ```rust,no_run
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let (_, code) = bucket.delete("/test.file").unwrap();
    /// assert_eq!(204, code);
    /// ```
    pub fn delete(&self, path: &str) -> S3Result<(Vec<u8>, u32)> {
        let command = Command::Delete;
        let request = Request::new(self, path, command);
        request.execute()
    }

    /// Put into an S3 bucket.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let aws_access = &"access_key";
    /// let aws_secret = &"secret_key";
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let content = "I want to go to S3".as_bytes();
    /// let (_, code) = bucket.put("/test.file", content, "text/plain").unwrap();
    /// assert_eq!(201, code);
    /// ```
    pub fn put(&self, path: &str, content: &[u8], content_type: &str) -> S3Result<(Vec<u8>, u32)> {
        let command = Command::Put {
            content,
            content_type,
        };
        let request = Request::new(self, path, command);
        request.execute()
    }

    fn _tags_xml(&self, tags: Vec<(&str, &str)>) -> String {
        let mut s = String::new();
        let content = tags
            .iter()
            .map(|&(name, value)| format!("<Tag><Key>{}</Key><Value>{}</Value></Tag>", name, value))
            .fold(String::new(), |mut a, b| {
                a.push_str(b.as_str());
                a
            });
        s.push_str("<Tagging><TagSet>");
        s.push_str(&content);
        s.push_str("</TagSet></Tagging>");

        s
    }

    /// Tag an S3 object.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let aws_access = &"access_key";
    /// let aws_secret = &"secret_key";
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let (_, code) = bucket.tag("/test.file", vec![("Tag1", "Value1"), ("Tag2", "Value2")]).unwrap();
    /// assert_eq!(201, code);
    /// ```
    pub fn tag(&self, path: &str, tags: Vec<(&str, &str)>) -> S3Result<(Vec<u8>, u32)> {
        let content = self._tags_xml(tags);
        let command = Command::Tag {
            tags: &content.to_string()
        };
        let request = Request::new(self, path, command);
        request.execute()
    }

    fn _list(&self,
             prefix: &str,
             delimiter: Option<&str>,
             continuation_token: Option<&str>)
             -> S3Result<(ListBucketResult, u32)> {
        let command = Command::List {
            prefix,
            delimiter,
            continuation_token,
        };
        let request = Request::new(self, "/", command);
        let result = request.execute()?;
        let result_string = String::from_utf8_lossy(&result.0);
        let deserialized: ListBucketResult = serde_xml::deserialize(result_string.as_bytes())?;
        Ok((deserialized, result.1))
    }

    /// List the contents of an S3 bucket.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use std::str;
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    /// let bucket_name = &"rust-s3-test";
    /// let aws_access = &"access_key";
    /// let aws_secret = &"secret_key";
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let results = bucket.list("/", Some("/")).unwrap();
    /// for (list, code) in results {
    ///     assert_eq!(200, code);
    ///     println!("{:?}", list);
    /// }
    /// ```
    pub fn list(&self, prefix: &str, delimiter: Option<&str>) -> S3Result<Vec<(ListBucketResult, u32)>> {
        let mut results = Vec::new();
        let mut result = self._list(prefix, delimiter, None)?;
        loop {
            results.push(result.clone());
            match result.0.next_continuation_token {
                Some(token) => result = self._list(prefix, delimiter, Some(&token))?,
                None => break,
            }
        }

        Ok(results)
    }

    /// Get a reference to the name of the S3 bucket.
    pub fn name(&self) -> String {
        self.name.to_string()
    }

    /// Get a reference to the hostname of the S3 API endpoint.
    pub fn host(&self) -> String {
        self.region.host()
    }

    pub fn self_host(&self) -> String {
        format!("{}.s3.amazonaws.com", self.name)
    }

    pub fn scheme(&self) -> String {
        self.region.scheme()
    }

    /// Get the region this object will connect to.
    pub fn region(&self) -> Region {
        self.region.clone()
    }

    /// Get a reference to the AWS access key.
    pub fn access_key(&self) -> String {
        self.credentials.access_key.clone()
    }

    /// Get a reference to the AWS secret key.
    pub fn secret_key(&self) -> String {
        self.credentials.secret_key.clone()
    }

    /// Get a reference to the AWS token.
    pub fn token(&self) -> Option<&str> {
        self.credentials.token.as_ref().map(|s| s.as_str())
    }

    /// Get a reference to the full [`Credentials`](struct.Credentials.html)
    /// object used by this `Bucket`.
    pub fn credentials(&self) -> &Credentials {
        &self.credentials
    }

    /// Change the credentials used by the Bucket, returning the existing
    /// credentials.
    pub fn set_credentials(&mut self, credentials: Credentials) -> Credentials {
        mem::replace(&mut self.credentials, credentials)
    }

    /// Add an extra header to send with requests to S3.
    ///
    /// Add an extra header to send with requests. Note that the library
    /// already sets a number of headers - headers set with this method will be
    /// overridden by the library headers:
    ///   * Host
    ///   * Content-Type
    ///   * Date
    ///   * Content-Length
    ///   * Authorization
    ///   * X-Amz-Content-Sha256
    ///   * X-Amz-Date
    pub fn add_header(&mut self, key: &str, value: &str) {
        self.extra_headers.insert(key.into(), value.into());
    }

    /// Get a reference to the extra headers to be passed to the S3 API.
    pub fn extra_headers(&self) -> &Headers {
        &self.extra_headers
    }

    /// Get a mutable reference to the extra headers to be passed to the S3
    /// API.
    pub fn extra_headers_mut(&mut self) -> &mut Headers {
        &mut self.extra_headers
    }

    /// Add an extra query pair to the URL used for S3 API access.
    pub fn add_query(&mut self, key: &str, value: &str) {
        self.extra_query.insert(key.into(), value.into());
    }

    /// Get a reference to the extra query pairs to be passed to the S3 API.
    pub fn extra_query(&self) -> &Query {
        &self.extra_query
    }

    /// Get a mutable reference to the extra query pairs to be passed to the S3
    /// API.
    pub fn extra_query_mut(&mut self) -> &mut Query {
        &mut self.extra_query
    }
}
<commit_msg>Pass by ref<commit_after>use std::collections::HashMap;
use std::mem;

use serde_xml;

use credentials::Credentials;
use command::Command;
use region::Region;
use request::{Request, Headers, Query};
use serde_types::{ListBucketResult, BucketLocationResult};
use error::S3Result;

/// # Example
/// ```
/// # // Fake  credentials so we don't access user's real credentials in tests
/// # use std::env;
/// # env::set_var("AWS_ACCESS_KEY_ID", "AKIAIOSFODNN7EXAMPLE");
/// # env::set_var("AWS_SECRET_ACCESS_KEY", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
/// use s3::bucket::Bucket;
/// use s3::credentials::Credentials;
///
/// let bucket_name = "rust-s3-test";
/// let region = "us-east-1".parse().unwrap();
/// let credentials = Credentials::default();
///
/// let bucket = Bucket::new(bucket_name, region, credentials);
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Bucket {
    pub name: String,
    pub region: Region,
    pub credentials: Credentials,
    pub extra_headers: Headers,
    pub extra_query: Query,
}

impl Bucket {
    /// Instantiate a new `Bucket`.
    ///
    /// # Example
    /// ```
    /// # // Fake  credentials so we don't access user's real credentials in tests
    /// # use std::env;
    /// # env::set_var("AWS_ACCESS_KEY_ID", "AKIAIOSFODNN7EXAMPLE");
    /// # env::set_var("AWS_SECRET_ACCESS_KEY", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = "rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    ///
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    /// ```
    pub fn new(name: &str, region: Region, credentials: Credentials) -> S3Result<Bucket> {
        Ok(Bucket {
            name: name.into(),
            region,
            credentials,
            extra_headers: HashMap::new(),
            extra_query: HashMap::new(),
        })
    }

    /// Gets file from an S3 path.
    ///
    /// # Example:
    ///
    /// ```rust,no_run
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = "rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let (data, code) = bucket.get("/test.file").unwrap();
    /// println!("Code: {}\nData: {:?}", code, data);
    /// ```
    pub fn get(&self, path: &str) -> S3Result<(Vec<u8>, u32)> {
        let command = Command::Get;
        let request = Request::new(self, path, command);
        request.execute()
    }

//// Get bucket location from S3
////
/// # Example
/// ```rust,no_run
/// # // Fake  credentials so we don't access user's real credentials in tests
/// # use std::env;
/// # env::set_var("AWS_ACCESS_KEY_ID", "AKIAIOSFODNN7EXAMPLE");
/// # env::set_var("AWS_SECRET_ACCESS_KEY", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
/// use s3::bucket::Bucket;
/// use s3::credentials::Credentials;
///
/// let bucket_name = "rust-s3-test";
/// let region = "eu-central-1".parse().unwrap();
/// let credentials = Credentials::default();
///
/// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
/// println!("{}", bucket.location().unwrap().0)
/// ```
    pub fn location(&self) -> S3Result<(Region, u32)> {
        let request = Request::new(self, "?location", Command::BucketOpGet);
        let result = request.execute()?;
        let result_string = String::from_utf8_lossy(&result.0);
        let region = match serde_xml::deserialize(result_string.as_bytes()) {
            Ok(r) => {
                let location_result: BucketLocationResult = r;
                location_result.region.parse()?
            }
            Err(e) => {
                if e.to_string() == "missing field `$value`" {
                    "us-east-1".parse()?
                } else {
                    bail!(e)
                }
            }
        };
        Ok((region, result.1))
    }

    /// Delete file from an S3 path.
    ///
    /// # Example:
    ///
    /// ```rust,no_run
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let (_, code) = bucket.delete("/test.file").unwrap();
    /// assert_eq!(204, code);
    /// ```
    pub fn delete(&self, path: &str) -> S3Result<(Vec<u8>, u32)> {
        let command = Command::Delete;
        let request = Request::new(self, path, command);
        request.execute()
    }

    /// Put into an S3 bucket.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let aws_access = &"access_key";
    /// let aws_secret = &"secret_key";
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let content = "I want to go to S3".as_bytes();
    /// let (_, code) = bucket.put("/test.file", content, "text/plain").unwrap();
    /// assert_eq!(201, code);
    /// ```
    pub fn put(&self, path: &str, content: &[u8], content_type: &str) -> S3Result<(Vec<u8>, u32)> {
        let command = Command::Put {
            content,
            content_type,
        };
        let request = Request::new(self, path, command);
        request.execute()
    }

    fn _tags_xml(&self, tags: &[(&str, &str)]) -> String {
        let mut s = String::new();
        let content = tags
            .iter()
            .map(|&(name, value)| format!("<Tag><Key>{}</Key><Value>{}</Value></Tag>", name, value))
            .fold(String::new(), |mut a, b| {
                a.push_str(b.as_str());
                a
            });
        s.push_str("<Tagging><TagSet>");
        s.push_str(&content);
        s.push_str("</TagSet></Tagging>");

        s
    }

    /// Tag an S3 object.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let aws_access = &"access_key";
    /// let aws_secret = &"secret_key";
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let (_, code) = bucket.tag("/test.file", &[("Tag1", "Value1"), ("Tag2", "Value2")]).unwrap();
    /// assert_eq!(201, code);
    /// ```
    pub fn tag(&self, path: &str, tags: &[(&str, &str)]) -> S3Result<(Vec<u8>, u32)> {
        let content = self._tags_xml(&tags);
        let command = Command::Tag {
            tags: &content.to_string()
        };
        let request = Request::new(self, path, command);
        request.execute()
    }

    fn _list(&self,
             prefix: &str,
             delimiter: Option<&str>,
             continuation_token: Option<&str>)
             -> S3Result<(ListBucketResult, u32)> {
        let command = Command::List {
            prefix,
            delimiter,
            continuation_token,
        };
        let request = Request::new(self, "/", command);
        let result = request.execute()?;
        let result_string = String::from_utf8_lossy(&result.0);
        let deserialized: ListBucketResult = serde_xml::deserialize(result_string.as_bytes())?;
        Ok((deserialized, result.1))
    }

    /// List the contents of an S3 bucket.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use std::str;
    /// use s3::bucket::Bucket;
    /// use s3::credentials::Credentials;
    /// let bucket_name = &"rust-s3-test";
    /// let aws_access = &"access_key";
    /// let aws_secret = &"secret_key";
    ///
    /// let bucket_name = &"rust-s3-test";
    /// let region = "us-east-1".parse().unwrap();
    /// let credentials = Credentials::default();
    /// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
    ///
    /// let results = bucket.list("/", Some("/")).unwrap();
    /// for (list, code) in results {
    ///     assert_eq!(200, code);
    ///     println!("{:?}", list);
    /// }
    /// ```
    pub fn list(&self, prefix: &str, delimiter: Option<&str>) -> S3Result<Vec<(ListBucketResult, u32)>> {
        let mut results = Vec::new();
        let mut result = self._list(prefix, delimiter, None)?;
        loop {
            results.push(result.clone());
            match result.0.next_continuation_token {
                Some(token) => result = self._list(prefix, delimiter, Some(&token))?,
                None => break,
            }
        }

        Ok(results)
    }

    /// Get a reference to the name of the S3 bucket.
    pub fn name(&self) -> String {
        self.name.to_string()
    }

    /// Get a reference to the hostname of the S3 API endpoint.
    pub fn host(&self) -> String {
        self.region.host()
    }

    pub fn self_host(&self) -> String {
        format!("{}.s3.amazonaws.com", self.name)
    }

    pub fn scheme(&self) -> String {
        self.region.scheme()
    }

    /// Get the region this object will connect to.
    pub fn region(&self) -> Region {
        self.region.clone()
    }

    /// Get a reference to the AWS access key.
    pub fn access_key(&self) -> String {
        self.credentials.access_key.clone()
    }

    /// Get a reference to the AWS secret key.
    pub fn secret_key(&self) -> String {
        self.credentials.secret_key.clone()
    }

    /// Get a reference to the AWS token.
    pub fn token(&self) -> Option<&str> {
        self.credentials.token.as_ref().map(|s| s.as_str())
    }

    /// Get a reference to the full [`Credentials`](struct.Credentials.html)
    /// object used by this `Bucket`.
    pub fn credentials(&self) -> &Credentials {
        &self.credentials
    }

    /// Change the credentials used by the Bucket, returning the existing
    /// credentials.
    pub fn set_credentials(&mut self, credentials: Credentials) -> Credentials {
        mem::replace(&mut self.credentials, credentials)
    }

    /// Add an extra header to send with requests to S3.
    ///
    /// Add an extra header to send with requests. Note that the library
    /// already sets a number of headers - headers set with this method will be
    /// overridden by the library headers:
    ///   * Host
    ///   * Content-Type
    ///   * Date
    ///   * Content-Length
    ///   * Authorization
    ///   * X-Amz-Content-Sha256
    ///   * X-Amz-Date
    pub fn add_header(&mut self, key: &str, value: &str) {
        self.extra_headers.insert(key.into(), value.into());
    }

    /// Get a reference to the extra headers to be passed to the S3 API.
    pub fn extra_headers(&self) -> &Headers {
        &self.extra_headers
    }

    /// Get a mutable reference to the extra headers to be passed to the S3
    /// API.
    pub fn extra_headers_mut(&mut self) -> &mut Headers {
        &mut self.extra_headers
    }

    /// Add an extra query pair to the URL used for S3 API access.
    pub fn add_query(&mut self, key: &str, value: &str) {
        self.extra_query.insert(key.into(), value.into());
    }

    /// Get a reference to the extra query pairs to be passed to the S3 API.
    pub fn extra_query(&self) -> &Query {
        &self.extra_query
    }

    /// Get a mutable reference to the extra query pairs to be passed to the S3
    /// API.
    pub fn extra_query_mut(&mut self) -> &mut Query {
        &mut self.extra_query
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate chrono;
extern crate env_logger;
extern crate futures;
extern crate openssl;
extern crate trust_dns;
extern crate trust_dns_compatibility;

use std::env;
use std::fs::File;
use std::io;
use std::io::Read;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};

use chrono::Duration;
use futures::Stream;
use openssl::rsa::Rsa;

use trust_dns::client::{Client, ClientConnection, SyncClient};
use trust_dns::udp::UdpClientConnection;
use trust_dns::op::ResponseCode;
use trust_dns::rr::{DNSClass, Name, Record, RData, RecordType};
use trust_dns::rr::dnssec::{Algorithm, Signer, KeyPair};
use trust_dns::rr::rdata::key::{KEY, KeyUsage};
use trust_dns_compatibility::named_process;

#[test]
#[allow(unused)]
fn test_get() {
    let (process, port) = named_process();
    let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port);
    let conn = UdpClientConnection::new(socket).unwrap();
    let client = SyncClient::new(conn);

    let name = Name::parse("www.example.com.", None).unwrap();
    let result = client.query(&name, DNSClass::IN, RecordType::A).expect(
        "query failed",
    );
    assert_eq!(result.response_code(), ResponseCode::NoError);
    assert_eq!(result.answers().len(), 1);
    assert_eq!(result.answers()[0].rr_type(), RecordType::A);

    let rdata = result.answers()[0].rdata();
    if let &RData::A(address) = rdata {
        assert_eq!(address, Ipv4Addr::new(127, 0, 0, 1));
    } else {
        assert!(false);
    }
}

fn create_sig0_ready_client<CC>(conn: CC) -> SyncClient
where
    CC: ClientConnection,
    <CC as ClientConnection>::MessageStream: Stream<Item = Vec<u8>, Error = io::Error> + 'static,
{
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let mut pem = File::open(format!(
        "{}/../compatibility-tests/tests/conf/Kupdate.example.com.+008+56935.pem",
        server_path
    )).expect("could not find pem file");

    let mut pem_buf = Vec::<u8>::new();
    pem.read_to_end(&mut pem_buf).expect("failed to read pem");
    let rsa = Rsa::private_key_from_pem(&pem_buf).expect("something wrong with key from pem");
    let key = KeyPair::from_rsa(rsa).unwrap();
    let sig0key = KEY::new(
        Default::default(),
        KeyUsage::Entity,
        Default::default(),
        Default::default(),
        Algorithm::RSASHA256,
        key.to_public_bytes().unwrap(),
    );

    let signer = Signer::sig0(
        sig0key,
        key,
        Name::from_labels(vec!["update", "example", "com"]),
    );

    assert_eq!(signer.calculate_key_tag().unwrap(), 56935_u16);

    SyncClient::with_signer(conn, signer)
}

#[test]
#[allow(unused)]
fn test_create() {
    let (process, port) = named_process();
    let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port);
    let conn = UdpClientConnection::new(socket).unwrap();

    let client = create_sig0_ready_client(conn);
    let origin = Name::from_labels(vec!["example", "com"]);

    // create a record
    let mut record = Record::with(
        Name::from_labels(vec!["new", "example", "com"]),
        RecordType::A,
        Duration::minutes(5).num_seconds() as u32,
    );
    record.set_rdata(RData::A(Ipv4Addr::new(100, 10, 100, 10)));

    let result = client.create(record.clone(), origin.clone()).expect(
        "create failed",
    );
    assert_eq!(result.response_code(), ResponseCode::NoError);
    let result = client
        .query(record.name(), record.dns_class(), record.rr_type())
        .expect("query failed");
    assert_eq!(result.response_code(), ResponseCode::NoError);
    assert_eq!(result.answers().len(), 1);
    assert_eq!(result.answers()[0], record);

    // trying to create again should error
    // TODO: it would be cool to make this
    let result = client.create(record.clone(), origin.clone()).expect(
        "create failed",
    );
    assert_eq!(result.response_code(), ResponseCode::YXRRSet);

    // will fail if already set and not the same value.
    let mut record = record.clone();
    record.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));

    let result = client.create(record.clone(), origin.clone()).expect(
        "create failed",
    );
    assert_eq!(result.response_code(), ResponseCode::YXRRSet);
}

// #[test]
// fn test_update() {
//     // named_process();
// }

// #[test]
// fn test_delete() {
//     // named_process();
// }<commit_msg>compatibility tests compiling<commit_after>// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate chrono;
extern crate env_logger;
extern crate futures;
extern crate openssl;
extern crate trust_dns;
extern crate trust_dns_compatibility;

use std::env;
use std::fs::File;
use std::io;
use std::io::Read;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};

use chrono::Duration;
use futures::Stream;
use openssl::rsa::Rsa;

use trust_dns::client::{Client, ClientConnection, SyncClient};
use trust_dns::udp::UdpClientConnection;
use trust_dns::op::ResponseCode;
use trust_dns::rr::{DNSClass, Name, Record, RData, RecordType};
use trust_dns::rr::dnssec::{Algorithm, MessageSigner, Signer, KeyPair};
use trust_dns::rr::rdata::key::{KEY, KeyUsage};
use trust_dns_compatibility::named_process;

#[test]
#[allow(unused)]
fn test_get() {
    let (process, port) = named_process();
    let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port);
    let conn = UdpClientConnection::new(socket).unwrap();
    let client = SyncClient::new(conn);

    let name = Name::parse("www.example.com.", None).unwrap();
    let result = client.query(&name, DNSClass::IN, RecordType::A).expect(
        "query failed",
    );
    assert_eq!(result.response_code(), ResponseCode::NoError);
    assert_eq!(result.answers().len(), 1);
    assert_eq!(result.answers()[0].rr_type(), RecordType::A);

    let rdata = result.answers()[0].rdata();
    if let &RData::A(address) = rdata {
        assert_eq!(address, Ipv4Addr::new(127, 0, 0, 1));
    } else {
        assert!(false);
    }
}

fn create_sig0_ready_client<CC>(conn: CC) -> SyncClient
where
    CC: ClientConnection,
    <CC as ClientConnection>::MessageStream: Stream<Item = Vec<u8>, Error = io::Error> + 'static,
{
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let mut pem = File::open(format!(
        "{}/../compatibility-tests/tests/conf/Kupdate.example.com.+008+56935.pem",
        server_path
    )).expect("could not find pem file");

    let mut pem_buf = Vec::<u8>::new();
    pem.read_to_end(&mut pem_buf).expect("failed to read pem");
    let rsa = Rsa::private_key_from_pem(&pem_buf).expect("something wrong with key from pem");
    let key = KeyPair::from_rsa(rsa).unwrap();
    let sig0key = KEY::new(
        Default::default(),
        KeyUsage::Entity,
        Default::default(),
        Default::default(),
        Algorithm::RSASHA256,
        key.to_public_bytes().unwrap(),
    );

    let signer = Signer::sig0(
        sig0key,
        key,
        Name::from_labels(vec!["update", "example", "com"]),
    );

    assert_eq!(signer.calculate_key_tag().unwrap(), 56935_u16);

    SyncClient::with_signer(conn, signer)
}

#[test]
#[allow(unused)]
fn test_create() {
    let (process, port) = named_process();
    let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port);
    let conn = UdpClientConnection::new(socket).unwrap();

    let client = create_sig0_ready_client(conn);
    let origin = Name::from_labels(vec!["example", "com"]);

    // create a record
    let mut record = Record::with(
        Name::from_labels(vec!["new", "example", "com"]),
        RecordType::A,
        Duration::minutes(5).num_seconds() as u32,
    );
    record.set_rdata(RData::A(Ipv4Addr::new(100, 10, 100, 10)));

    let result = client.create(record.clone(), origin.clone()).expect(
        "create failed",
    );
    assert_eq!(result.response_code(), ResponseCode::NoError);
    let result = client
        .query(record.name(), record.dns_class(), record.rr_type())
        .expect("query failed");
    assert_eq!(result.response_code(), ResponseCode::NoError);
    assert_eq!(result.answers().len(), 1);
    assert_eq!(result.answers()[0], record);

    // trying to create again should error
    // TODO: it would be cool to make this
    let result = client.create(record.clone(), origin.clone()).expect(
        "create failed",
    );
    assert_eq!(result.response_code(), ResponseCode::YXRRSet);

    // will fail if already set and not the same value.
    let mut record = record.clone();
    record.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));

    let result = client.create(record.clone(), origin.clone()).expect(
        "create failed",
    );
    assert_eq!(result.response_code(), ResponseCode::YXRRSet);
}

// #[test]
// fn test_update() {
//     // named_process();
// }

// #[test]
// fn test_delete() {
//     // named_process();
// }<|endoftext|>


<commit_before>//! A stably addressed token buffer supporting efficient traversal based on a
//! cheaply copyable cursor.
//!
//! *This module is available if Syn is built with the `"parsing"` feature.*

// This module is heavily commented as it contains the only unsafe code in Syn,
// and caution should be used when editing it. The public-facing interface is
// 100% safe but the implementation is fragile internally.

#[cfg(all(
    not(all(target_arch = "wasm32", target_os = "unknown")),
    feature = "proc-macro"
))]
use proc_macro as pm;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};

use std::marker::PhantomData;
use std::ptr;

use Lifetime;

/// Internal type which is used instead of `TokenTree` to represent a token tree
/// within a `TokenBuffer`.
enum Entry {
    // Mimicking types from proc-macro.
    Group(Group, TokenBuffer),
    Ident(Ident),
    Punct(Punct),
    Literal(Literal),
    // End entries contain a raw pointer to the entry from the containing
    // token tree, or null if this is the outermost level.
    End(*const Entry),
}

/// A buffer that can be efficiently traversed multiple times, unlike
/// `TokenStream` which requires a deep copy in order to traverse more than
/// once.
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
pub struct TokenBuffer {
    // NOTE: Do not derive clone on this - there are raw pointers inside which
    // will be messed up. Moving the `TokenBuffer` itself is safe as the actual
    // backing slices won't be moved.
    data: Box<[Entry]>,
}

impl TokenBuffer {
    // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT
    // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE.
    fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer {
        // Build up the entries list, recording the locations of any Groups
        // in the list to be processed later.
        let mut entries = Vec::new();
        let mut seqs = Vec::new();
        for tt in stream {
            match tt {
                TokenTree::Ident(sym) => {
                    entries.push(Entry::Ident(sym));
                }
                TokenTree::Punct(op) => {
                    entries.push(Entry::Punct(op));
                }
                TokenTree::Literal(l) => {
                    entries.push(Entry::Literal(l));
                }
                TokenTree::Group(g) => {
                    // Record the index of the interesting entry, and store an
                    // `End(null)` there temporarially.
                    seqs.push((entries.len(), g));
                    entries.push(Entry::End(ptr::null()));
                }
            }
        }
        // Add an `End` entry to the end with a reference to the enclosing token
        // stream which was passed in.
        entries.push(Entry::End(up));

        // NOTE: This is done to ensure that we don't accidentally modify the
        // length of the backing buffer. The backing buffer must remain at a
        // constant address after this point, as we are going to store a raw
        // pointer into it.
        let mut entries = entries.into_boxed_slice();
        for (idx, group) in seqs {
            // We know that this index refers to one of the temporary
            // `End(null)` entries, and we know that the last entry is
            // `End(up)`, so the next index is also valid.
            let seq_up = &entries[idx + 1] as *const Entry;

            // The end entry stored at the end of this Entry::Group should
            // point to the Entry which follows the Group in the list.
            let inner = Self::inner_new(group.stream(), seq_up);
            entries[idx] = Entry::Group(group, inner);
        }

        TokenBuffer { data: entries }
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `TokenStream`.
    ///
    /// *This method is available if Syn is built with both the `"parsing"` and
    /// `"proc-macro"` features.*
    #[cfg(all(
        not(all(target_arch = "wasm32", target_os = "unknown")),
        feature = "proc-macro"
    ))]
    pub fn new(stream: pm::TokenStream) -> TokenBuffer {
        Self::new2(stream.into())
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `TokenStream`.
    pub fn new2(stream: TokenStream) -> TokenBuffer {
        Self::inner_new(stream, ptr::null())
    }

    /// Creates a cursor referencing the first token in the buffer and able to
    /// traverse until the end of the buffer.
    pub fn begin(&self) -> Cursor {
        unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) }
    }
}

/// A cheaply copyable cursor into a `TokenBuffer`.
///
/// This cursor holds a shared reference into the immutable data which is used
/// internally to represent a `TokenStream`, and can be efficiently manipulated
/// and copied around.
///
/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer`
/// object and get a cursor to its first token with `begin()`.
///
/// Two cursors are equal if they have the same location in the same input
/// stream, and have the same scope.
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Cursor<'a> {
    // The current entry which the `Cursor` is pointing at.
    ptr: *const Entry,
    // This is the only `Entry::End(..)` object which this cursor is allowed to
    // point at. All other `End` objects are skipped over in `Cursor::create`.
    scope: *const Entry,
    // Cursor is covariant in 'a. This field ensures that our pointers are still
    // valid.
    marker: PhantomData<&'a Entry>,
}

impl<'a> Cursor<'a> {
    /// Creates a cursor referencing a static empty TokenStream.
    pub fn empty() -> Self {
        // It's safe in this situation for us to put an `Entry` object in global
        // storage, despite it not actually being safe to send across threads
        // (`Ident` is a reference into a thread-local table). This is because
        // this entry never includes a `Ident` object.
        //
        // This wrapper struct allows us to break the rules and put a `Sync`
        // object in global storage.
        struct UnsafeSyncEntry(Entry);
        unsafe impl Sync for UnsafeSyncEntry {}
        static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry));

        Cursor {
            ptr: &EMPTY_ENTRY.0,
            scope: &EMPTY_ENTRY.0,
            marker: PhantomData,
        }
    }

    /// This create method intelligently exits non-explicitly-entered
    /// `None`-delimited scopes when the cursor reaches the end of them,
    /// allowing for them to be treated transparently.
    unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
        // NOTE: If we're looking at a `End(..)`, we want to advance the cursor
        // past it, unless `ptr == scope`, which means that we're at the edge of
        // our cursor's scope. We should only have `ptr != scope` at the exit
        // from None-delimited groups entered with `ignore_none`.
        while let Entry::End(exit) = *ptr {
            if ptr == scope {
                break;
            }
            ptr = exit;
        }

        Cursor {
            ptr: ptr,
            scope: scope,
            marker: PhantomData,
        }
    }

    /// Get the current entry.
    fn entry(self) -> &'a Entry {
        unsafe { &*self.ptr }
    }

    /// Bump the cursor to point at the next token after the current one. This
    /// is undefined behavior if the cursor is currently looking at an
    /// `Entry::End`.
    unsafe fn bump(self) -> Cursor<'a> {
        Cursor::create(self.ptr.offset(1), self.scope)
    }

    /// If the cursor is looking at a `None`-delimited group, move it to look at
    /// the first token inside instead. If the group is empty, this will move
    /// the cursor past the `None`-delimited group.
    ///
    /// WARNING: This mutates its argument.
    fn ignore_none(&mut self) {
        if let Entry::Group(ref group, ref buf) = *self.entry() {
            if group.delimiter() == Delimiter::None {
                // NOTE: We call `Cursor::create` here to make sure that
                // situations where we should immediately exit the span after
                // entering it are handled correctly.
                unsafe {
                    *self = Cursor::create(&buf.data[0], self.scope);
                }
            }
        }
    }

    /// Checks whether the cursor is currently pointing at the end of its valid
    /// scope.
    #[inline]
    pub fn eof(self) -> bool {
        // We're at eof if we're at the end of our scope.
        self.ptr == self.scope
    }

    /// If the cursor is pointing at a `Group` with the given delimiter, returns
    /// a cursor into that group and one pointing to the next `TokenTree`.
    pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
        // If we're not trying to enter a none-delimited group, we want to
        // ignore them. We have to make sure to _not_ ignore them when we want
        // to enter them, of course. For obvious reasons.
        if delim != Delimiter::None {
            self.ignore_none();
        }

        if let Entry::Group(ref group, ref buf) = *self.entry() {
            if group.delimiter() == delim {
                return Some((buf.begin(), group.span(), unsafe { self.bump() }));
            }
        }

        None
    }

    /// If the cursor is pointing at a `Ident`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> {
        self.ignore_none();
        match *self.entry() {
            Entry::Ident(ref ident) => Some((ident.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at an `Punct`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
        self.ignore_none();
        match *self.entry() {
            Entry::Punct(ref op) if op.as_char() != '\'' => {
                Some((op.clone(), unsafe { self.bump() }))
            }
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Literal`, return it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
        self.ignore_none();
        match *self.entry() {
            Entry::Literal(ref lit) => Some((lit.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Lifetime`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> {
        self.ignore_none();
        match *self.entry() {
            Entry::Punct(ref op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
                let next = unsafe { self.bump() };
                match next.ident() {
                    Some((ident, rest)) => {
                        let lifetime = Lifetime {
                            apostrophe: op.span(),
                            ident: ident,
                        };
                        Some((lifetime, rest))
                    }
                    None => None,
                }
            }
            _ => None,
        }
    }

    /// Copies all remaining tokens visible from this cursor into a
    /// `TokenStream`.
    pub fn token_stream(self) -> TokenStream {
        let mut tts = Vec::new();
        let mut cursor = self;
        while let Some((tt, rest)) = cursor.token_tree() {
            tts.push(tt);
            cursor = rest;
        }
        tts.into_iter().collect()
    }

    /// If the cursor is pointing at a `TokenTree`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    ///
    /// Returns `None` if the cursor has reached the end of its stream.
    ///
    /// This method does not treat `None`-delimited groups as transparent, and
    /// will return a `Group(None, ..)` if the cursor is looking at one.
    pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
        let tree = match *self.entry() {
            Entry::Group(ref group, _) => group.clone().into(),
            Entry::Literal(ref lit) => lit.clone().into(),
            Entry::Ident(ref ident) => ident.clone().into(),
            Entry::Punct(ref op) => op.clone().into(),
            Entry::End(..) => {
                return None;
            }
        };

        Some((tree, unsafe { self.bump() }))
    }

    /// Returns the `Span` of the current token, or `Span::call_site()` if this
    /// cursor points to eof.
    pub fn span(self) -> Span {
        match *self.entry() {
            Entry::Group(ref group, _) => group.span(),
            Entry::Literal(ref l) => l.span(),
            Entry::Ident(ref t) => t.span(),
            Entry::Punct(ref o) => o.span(),
            Entry::End(..) => Span::call_site(),
        }
    }
}
<commit_msg>There is now unsafe code outside of buffer.rs<commit_after>//! A stably addressed token buffer supporting efficient traversal based on a
//! cheaply copyable cursor.
//!
//! *This module is available if Syn is built with the `"parsing"` feature.*

// This module is heavily commented as it contains most of the unsafe code in
// Syn, and caution should be used when editing it. The public-facing interface
// is 100% safe but the implementation is fragile internally.

#[cfg(all(
    not(all(target_arch = "wasm32", target_os = "unknown")),
    feature = "proc-macro"
))]
use proc_macro as pm;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};

use std::marker::PhantomData;
use std::ptr;

use Lifetime;

/// Internal type which is used instead of `TokenTree` to represent a token tree
/// within a `TokenBuffer`.
enum Entry {
    // Mimicking types from proc-macro.
    Group(Group, TokenBuffer),
    Ident(Ident),
    Punct(Punct),
    Literal(Literal),
    // End entries contain a raw pointer to the entry from the containing
    // token tree, or null if this is the outermost level.
    End(*const Entry),
}

/// A buffer that can be efficiently traversed multiple times, unlike
/// `TokenStream` which requires a deep copy in order to traverse more than
/// once.
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
pub struct TokenBuffer {
    // NOTE: Do not derive clone on this - there are raw pointers inside which
    // will be messed up. Moving the `TokenBuffer` itself is safe as the actual
    // backing slices won't be moved.
    data: Box<[Entry]>,
}

impl TokenBuffer {
    // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT
    // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE.
    fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer {
        // Build up the entries list, recording the locations of any Groups
        // in the list to be processed later.
        let mut entries = Vec::new();
        let mut seqs = Vec::new();
        for tt in stream {
            match tt {
                TokenTree::Ident(sym) => {
                    entries.push(Entry::Ident(sym));
                }
                TokenTree::Punct(op) => {
                    entries.push(Entry::Punct(op));
                }
                TokenTree::Literal(l) => {
                    entries.push(Entry::Literal(l));
                }
                TokenTree::Group(g) => {
                    // Record the index of the interesting entry, and store an
                    // `End(null)` there temporarially.
                    seqs.push((entries.len(), g));
                    entries.push(Entry::End(ptr::null()));
                }
            }
        }
        // Add an `End` entry to the end with a reference to the enclosing token
        // stream which was passed in.
        entries.push(Entry::End(up));

        // NOTE: This is done to ensure that we don't accidentally modify the
        // length of the backing buffer. The backing buffer must remain at a
        // constant address after this point, as we are going to store a raw
        // pointer into it.
        let mut entries = entries.into_boxed_slice();
        for (idx, group) in seqs {
            // We know that this index refers to one of the temporary
            // `End(null)` entries, and we know that the last entry is
            // `End(up)`, so the next index is also valid.
            let seq_up = &entries[idx + 1] as *const Entry;

            // The end entry stored at the end of this Entry::Group should
            // point to the Entry which follows the Group in the list.
            let inner = Self::inner_new(group.stream(), seq_up);
            entries[idx] = Entry::Group(group, inner);
        }

        TokenBuffer { data: entries }
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `TokenStream`.
    ///
    /// *This method is available if Syn is built with both the `"parsing"` and
    /// `"proc-macro"` features.*
    #[cfg(all(
        not(all(target_arch = "wasm32", target_os = "unknown")),
        feature = "proc-macro"
    ))]
    pub fn new(stream: pm::TokenStream) -> TokenBuffer {
        Self::new2(stream.into())
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `TokenStream`.
    pub fn new2(stream: TokenStream) -> TokenBuffer {
        Self::inner_new(stream, ptr::null())
    }

    /// Creates a cursor referencing the first token in the buffer and able to
    /// traverse until the end of the buffer.
    pub fn begin(&self) -> Cursor {
        unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) }
    }
}

/// A cheaply copyable cursor into a `TokenBuffer`.
///
/// This cursor holds a shared reference into the immutable data which is used
/// internally to represent a `TokenStream`, and can be efficiently manipulated
/// and copied around.
///
/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer`
/// object and get a cursor to its first token with `begin()`.
///
/// Two cursors are equal if they have the same location in the same input
/// stream, and have the same scope.
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Cursor<'a> {
    // The current entry which the `Cursor` is pointing at.
    ptr: *const Entry,
    // This is the only `Entry::End(..)` object which this cursor is allowed to
    // point at. All other `End` objects are skipped over in `Cursor::create`.
    scope: *const Entry,
    // Cursor is covariant in 'a. This field ensures that our pointers are still
    // valid.
    marker: PhantomData<&'a Entry>,
}

impl<'a> Cursor<'a> {
    /// Creates a cursor referencing a static empty TokenStream.
    pub fn empty() -> Self {
        // It's safe in this situation for us to put an `Entry` object in global
        // storage, despite it not actually being safe to send across threads
        // (`Ident` is a reference into a thread-local table). This is because
        // this entry never includes a `Ident` object.
        //
        // This wrapper struct allows us to break the rules and put a `Sync`
        // object in global storage.
        struct UnsafeSyncEntry(Entry);
        unsafe impl Sync for UnsafeSyncEntry {}
        static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry));

        Cursor {
            ptr: &EMPTY_ENTRY.0,
            scope: &EMPTY_ENTRY.0,
            marker: PhantomData,
        }
    }

    /// This create method intelligently exits non-explicitly-entered
    /// `None`-delimited scopes when the cursor reaches the end of them,
    /// allowing for them to be treated transparently.
    unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
        // NOTE: If we're looking at a `End(..)`, we want to advance the cursor
        // past it, unless `ptr == scope`, which means that we're at the edge of
        // our cursor's scope. We should only have `ptr != scope` at the exit
        // from None-delimited groups entered with `ignore_none`.
        while let Entry::End(exit) = *ptr {
            if ptr == scope {
                break;
            }
            ptr = exit;
        }

        Cursor {
            ptr: ptr,
            scope: scope,
            marker: PhantomData,
        }
    }

    /// Get the current entry.
    fn entry(self) -> &'a Entry {
        unsafe { &*self.ptr }
    }

    /// Bump the cursor to point at the next token after the current one. This
    /// is undefined behavior if the cursor is currently looking at an
    /// `Entry::End`.
    unsafe fn bump(self) -> Cursor<'a> {
        Cursor::create(self.ptr.offset(1), self.scope)
    }

    /// If the cursor is looking at a `None`-delimited group, move it to look at
    /// the first token inside instead. If the group is empty, this will move
    /// the cursor past the `None`-delimited group.
    ///
    /// WARNING: This mutates its argument.
    fn ignore_none(&mut self) {
        if let Entry::Group(ref group, ref buf) = *self.entry() {
            if group.delimiter() == Delimiter::None {
                // NOTE: We call `Cursor::create` here to make sure that
                // situations where we should immediately exit the span after
                // entering it are handled correctly.
                unsafe {
                    *self = Cursor::create(&buf.data[0], self.scope);
                }
            }
        }
    }

    /// Checks whether the cursor is currently pointing at the end of its valid
    /// scope.
    #[inline]
    pub fn eof(self) -> bool {
        // We're at eof if we're at the end of our scope.
        self.ptr == self.scope
    }

    /// If the cursor is pointing at a `Group` with the given delimiter, returns
    /// a cursor into that group and one pointing to the next `TokenTree`.
    pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
        // If we're not trying to enter a none-delimited group, we want to
        // ignore them. We have to make sure to _not_ ignore them when we want
        // to enter them, of course. For obvious reasons.
        if delim != Delimiter::None {
            self.ignore_none();
        }

        if let Entry::Group(ref group, ref buf) = *self.entry() {
            if group.delimiter() == delim {
                return Some((buf.begin(), group.span(), unsafe { self.bump() }));
            }
        }

        None
    }

    /// If the cursor is pointing at a `Ident`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> {
        self.ignore_none();
        match *self.entry() {
            Entry::Ident(ref ident) => Some((ident.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at an `Punct`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
        self.ignore_none();
        match *self.entry() {
            Entry::Punct(ref op) if op.as_char() != '\'' => {
                Some((op.clone(), unsafe { self.bump() }))
            }
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Literal`, return it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
        self.ignore_none();
        match *self.entry() {
            Entry::Literal(ref lit) => Some((lit.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Lifetime`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> {
        self.ignore_none();
        match *self.entry() {
            Entry::Punct(ref op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
                let next = unsafe { self.bump() };
                match next.ident() {
                    Some((ident, rest)) => {
                        let lifetime = Lifetime {
                            apostrophe: op.span(),
                            ident: ident,
                        };
                        Some((lifetime, rest))
                    }
                    None => None,
                }
            }
            _ => None,
        }
    }

    /// Copies all remaining tokens visible from this cursor into a
    /// `TokenStream`.
    pub fn token_stream(self) -> TokenStream {
        let mut tts = Vec::new();
        let mut cursor = self;
        while let Some((tt, rest)) = cursor.token_tree() {
            tts.push(tt);
            cursor = rest;
        }
        tts.into_iter().collect()
    }

    /// If the cursor is pointing at a `TokenTree`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    ///
    /// Returns `None` if the cursor has reached the end of its stream.
    ///
    /// This method does not treat `None`-delimited groups as transparent, and
    /// will return a `Group(None, ..)` if the cursor is looking at one.
    pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
        let tree = match *self.entry() {
            Entry::Group(ref group, _) => group.clone().into(),
            Entry::Literal(ref lit) => lit.clone().into(),
            Entry::Ident(ref ident) => ident.clone().into(),
            Entry::Punct(ref op) => op.clone().into(),
            Entry::End(..) => {
                return None;
            }
        };

        Some((tree, unsafe { self.bump() }))
    }

    /// Returns the `Span` of the current token, or `Span::call_site()` if this
    /// cursor points to eof.
    pub fn span(self) -> Span {
        match *self.entry() {
            Entry::Group(ref group, _) => group.span(),
            Entry::Literal(ref l) => l.span(),
            Entry::Ident(ref t) => t.span(),
            Entry::Punct(ref o) => o.span(),
            Entry::End(..) => Span::call_site(),
        }
    }
}
<|endoftext|>