<commit_before>//! Madgwick's orientation filter
//!
//! This demo runs Madgwick's orientation filter and logs the orientation of the board as
//! quaternions via the ITM. The data is encoded in binary format and logged as COBS frame. The
//! binary format is as follows:
//!
//! - `w`: `f32`, LE (Little Endian), 4 bytes
//! - `x`: `f32`, LE, 4 bytes
//! - `y`: `f32`, LE, 4 bytes
//! - `z`: `f32`, LE, 4 bytes
//!
//! where the quaternion is the tuple `(w, x, y, z)`
//!
//! The suggested way to receive this data is to connect the F3 SWO pin to a UART to USB converter
//! and then to read out the associated device file using `itmdump`. Make sure you configure the
//! serial device before calling `itmdump`. The commands to run are:
//!
//! ``` console
//! $ stty -F /dev/ttyUSB0 raw 2000000 -echo
//!
//! $ itmdump -f /dev/ttyUSB0 > data.txt
//! ```
//!
//! You can pipe the quaternions through the `viz` program (shipped with this crate) to get real
//! time [visualization]. The command to run is:
//!
//! [visualization]: https://mobile.twitter.com/japaricious/status/962770003325005824
//!
//! ``` console
//! $ itmdump -f /dev/ttyUSB0 | viz
//! ```
//!
//! ```
//! // #![deny(unsafe_code)]
//! #![deny(warnings)]
//! #![no_main]
//! #![no_std]
//!
//! extern crate panic_semihosting;
//!
//! use core::{f32::consts::PI, ptr};
//!
//! use aligned::Aligned;
//! use byteorder::{ByteOrder, LE};
//! use cast::{f32, i32};
//! use cortex_m::itm;
//! use cortex_m_rt::entry;
//! use f3::{
//!     hal::{i2c::I2c, prelude::*, spi::Spi, stm32f30x, timer::Timer},
//!     l3gd20::{self, Odr},
//!     lsm303dlhc::{AccelOdr, MagOdr},
//!     L3gd20, Lsm303dlhc,
//! };
//! use madgwick::{F32x3, Marg};
//! use nb::block;
//!
//! // Number of samples to use for gyroscope calibration
//! const NSAMPLES: i32 = 256;
//!
//! // Magnetometer calibration parameters
//! // NOTE you need to use the right parameters for *your* magnetometer
//! // You can use the `log-sensors` example to calibrate your magnetometer. The producer is explained
//! // in https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration
//! const M_BIAS_X: f32 = -34.;
//! const M_SCALE_X: f32 = 650.;
//!
//! const M_BIAS_Y: f32 = -70.;
//! const M_SCALE_Y: f32 = 636.;
//!
//! const M_BIAS_Z: f32 = -37.5;
//! const M_SCALE_Z: f32 = 589.5;
//!
//! // Sensitivities of the accelerometer and gyroscope, respectively
//! const K_G: f32 = 2. / (1 << 15) as f32; // LSB -> g
//! const K_AR: f32 = 8.75e-3 * PI / 180.; // LSB -> rad/s
//!
//! // Madgwick filter parameters
//! const SAMPLE_FREQ: u32 = 220;
//! const BETA: f32 = 1e-3;
//!
//! #[entry]
//! fn main() -> ! {
//!     let mut cp = cortex_m::Peripherals::take().unwrap();
//!     let dp = stm32f30x::Peripherals::take().unwrap();
//!
//!     let mut flash = dp.FLASH.constrain();
//!     let mut rcc = dp.RCC.constrain();
//!
//!     let clocks = rcc
//!         .cfgr
//!         .sysclk(64.mhz())
//!         .pclk1(32.mhz())
//!         .freeze(&mut flash.acr);
//!
//!     // enable ITM
//!     // TODO this should be some high level API in the cortex-m crate
//!     unsafe {
//!         // enable TPIU and ITM
//!         cp.DCB.demcr.modify(|r| r | (1 << 24));
//!
//!         // prescaler
//!         let swo_freq = 2_000_000;
//!         cp.TPIU.acpr.write((clocks.sysclk().0 / swo_freq) - 1);
//!
//!         // SWO NRZ
//!         cp.TPIU.sppr.write(2);
//!
//!         cp.TPIU.ffcr.modify(|r| r & !(1 << 1));
//!
//!         // STM32 specific: enable tracing in the DBGMCU_CR register
//!         const DBGMCU_CR: *mut u32 = 0xe0042004 as *mut u32;
//!         let r = ptr::read_volatile(DBGMCU_CR);
//!         ptr::write_volatile(DBGMCU_CR, r | (1 << 5));
//!
//!         // unlock the ITM
//!         cp.ITM.lar.write(0xC5ACCE55);
//!
//!         cp.ITM.tcr.write(
//!             (0b000001 << 16) | // TraceBusID
//!             (1 << 3) | // enable SWO output
//!             (1 << 0), // enable the ITM
//!         );
//!
//!         // enable stimulus port 0
//!         cp.ITM.ter[0].write(1);
//!     }
//!
//!     let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);
//!     let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);
//!     let mut gpioe = dp.GPIOE.split(&mut rcc.ahb);
//!
//!     let mut nss = gpioe
//!         .pe3
//!         .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
//!     nss.set_high();
//!     let mut led = gpioe
//!         .pe9
//!         .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
//!
//!     let sck = gpioa.pa5.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!     let miso = gpioa.pa6.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!     let mosi = gpioa.pa7.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!
//!     let spi = Spi::spi1(
//!         dp.SPI1,
//!         (sck, miso, mosi),
//!         l3gd20::MODE,
//!         1.mhz(),
//!         clocks,
//!         &mut rcc.apb2,
//!     );
//!
//!     let mut l3gd20 = L3gd20::new(spi, nss).unwrap();
//!
//!     l3gd20.set_odr(Odr::Hz380).unwrap();
//!
//!     let scl = gpiob.pb6.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
//!     let sda = gpiob.pb7.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
//!
//!     let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 400.khz(), clocks, &mut rcc.apb1);
//!
//!     let mut lsm303dlhc = Lsm303dlhc::new(i2c).unwrap();
//!
//!     lsm303dlhc.accel_odr(AccelOdr::Hz400).unwrap();
//!     lsm303dlhc.mag_odr(MagOdr::Hz220).unwrap();
//!
//!     let mut timer = Timer::tim2(dp.TIM2, 380.hz(), clocks, &mut rcc.apb1);
//!
//!     // Calibrate the gyroscope
//!     let mut ar_bias_x = 0;
//!     let mut ar_bias_y = 0;
//!     let mut ar_bias_z = 0;
//!     for _ in 0..NSAMPLES {
//!         block!(timer.wait()).unwrap();
//!
//!         let ar = l3gd20.gyro().unwrap();
//!
//!         ar_bias_x += i32(ar.x);
//!         ar_bias_y += i32(ar.y);
//!         ar_bias_z += i32(ar.z);
//!     }
//!     let ar_bias_x = (ar_bias_x / NSAMPLES) as i16;
//!     let ar_bias_y = (ar_bias_y / NSAMPLES) as i16;
//!     let ar_bias_z = (ar_bias_z / NSAMPLES) as i16;
//!
//!     // Turn on the LED after calibrating the gyroscope
//!     led.set_high();
//!
//!     let mut marg = Marg::new(BETA, 1. / f32(SAMPLE_FREQ));
//!     let mut timer = Timer::tim2(timer.free(), SAMPLE_FREQ.hz(), clocks, &mut rcc.apb1);
//!
//!     let mut tx_buf: Aligned<u32, [u8; 18]> = Aligned([0; 18]);
//!     loop {
//!         block!(timer.wait()).unwrap();
//!
//!         let m = lsm303dlhc.mag().unwrap();
//!         let ar = l3gd20.gyro().unwrap();
//!         let g = lsm303dlhc.accel().unwrap();
//!
//!         let m_x = (f32(m.x) - M_BIAS_X) / M_SCALE_X;
//!         let m_y = (f32(m.y) - M_BIAS_Y) / M_SCALE_Y;
//!         let m_z = (f32(m.z) - M_BIAS_Z) / M_SCALE_Z;
//!
//!         // Fix the X Y Z components of the magnetometer so they match the gyro axes
//!         let m = F32x3 {
//!             x: m_y,
//!             y: -m_x,
//!             z: m_z,
//!         };
//!
//!         let ar_x = f32(ar.x - ar_bias_x) * K_AR;
//!         let ar_y = f32(ar.y - ar_bias_y) * K_AR;
//!         let ar_z = f32(ar.z - ar_bias_z) * K_AR;
//!         let ar = F32x3 {
//!             x: ar_x,
//!             y: ar_y,
//!             z: ar_z,
//!         };
//!
//!         // Fix the X Y Z components of the accelerometer so they match the gyro axes
//!         let g_x = f32(g.x) * K_G;
//!         let g_y = f32(g.y) * K_G;
//!         let g_z = f32(g.z) * K_G;
//!         let g = F32x3 {
//!             x: g_y,
//!             y: -g_x,
//!             z: g_z,
//!         };
//!
//!         // Run the filter
//!         let quat = marg.update(m, ar, g);
//!
//!         // Serialize the quaternion
//!         let mut start = 0;
//!         let mut buf = [0; 16];
//!         LE::write_f32(&mut buf[start..start + 4], quat.0);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.1);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.2);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.3);
//!         // start += 4;
//!
//!         // Log data
//!         cobs::encode(&buf, &mut tx_buf.array);
//!
//!         itm::write_aligned(&mut cp.ITM.stim[0], &tx_buf);
//!     }
//! }
//! ```
// Auto-generated. Do not modify.
<commit_msg>re-generate example docs<commit_after>//! Madgwick's orientation filter
//!
//! This demo runs Madgwick's orientation filter and logs the orientation of the board as
//! quaternions via the ITM. The data is encoded in binary format and logged as COBS frame. The
//! binary format is as follows:
//!
//! - `w`: `f32`, LE (Little Endian), 4 bytes
//! - `x`: `f32`, LE, 4 bytes
//! - `y`: `f32`, LE, 4 bytes
//! - `z`: `f32`, LE, 4 bytes
//!
//! where the quaternion is the tuple `(w, x, y, z)`
//!
//! The suggested way to receive this data is to connect the F3 SWO pin to a UART to USB converter
//! and then to read out the associated device file using `itmdump`. Make sure you configure the
//! serial device before calling `itmdump`. The commands to run are:
//!
//! ``` console
//! $ stty -F /dev/ttyUSB0 raw 2000000 -echo
//!
//! $ itmdump -f /dev/ttyUSB0 > data.txt
//! ```
//!
//! You can pipe the quaternions through the `viz` program (shipped with this crate) to get real
//! time [visualization]. The command to run is:
//!
//! [visualization]: https://mobile.twitter.com/japaricious/status/962770003325005824
//!
//! ``` console
//! $ itmdump -f /dev/ttyUSB0 | viz
//! ```
//!
//! ```
//! // #![deny(unsafe_code)]
//! #![deny(warnings)]
//! #![no_main]
//! #![no_std]
//!
//! extern crate panic_semihosting;
//!
//! use core::{f32::consts::PI, ptr};
//!
//! use aligned::Aligned;
//! use byteorder::{ByteOrder, LE};
//! use cast::{f32, i32};
//! use cortex_m::itm;
//! use cortex_m_rt::entry;
//! use f3::{
//!     hal::{i2c::I2c, prelude::*, spi::Spi, stm32f30x, timer::Timer},
//!     l3gd20::{self, Odr},
//!     lsm303dlhc::{AccelOdr, MagOdr},
//!     L3gd20, Lsm303dlhc,
//! };
//! use madgwick::{F32x3, Marg};
//! use nb::block;
//!
//! // Number of samples to use for gyroscope calibration
//! const NSAMPLES: i32 = 256;
//!
//! // Magnetometer calibration parameters
//! // NOTE you need to use the right parameters for *your* magnetometer
//! // You can use the `log-sensors` example to calibrate your magnetometer. The producer is explained
//! // in https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration
//! const M_BIAS_X: f32 = -183.;
//! const M_SCALE_X: f32 = 435.;
//!
//! const M_BIAS_Y: f32 = -172.;
//! const M_SCALE_Y: f32 = 507.;
//!
//! const M_BIAS_Z: f32 = -136.;
//! const M_SCALE_Z: f32 = 632.;
//!
//! // Sensitivities of the accelerometer and gyroscope, respectively
//! const K_G: f32 = 2. / (1 << 15) as f32; // LSB -> g
//! const K_AR: f32 = 8.75e-3 * PI / 180.; // LSB -> rad/s
//!
//! // Madgwick filter parameters
//! const SAMPLE_FREQ: u32 = 220;
//! const BETA: f32 = 1e-3;
//!
//! #[entry]
//! fn main() -> ! {
//!     let mut cp = cortex_m::Peripherals::take().unwrap();
//!     let dp = stm32f30x::Peripherals::take().unwrap();
//!
//!     let mut flash = dp.FLASH.constrain();
//!     let mut rcc = dp.RCC.constrain();
//!
//!     let clocks = rcc
//!         .cfgr
//!         .sysclk(64.mhz())
//!         .pclk1(32.mhz())
//!         .freeze(&mut flash.acr);
//!
//!     // enable ITM
//!     // TODO this should be some high level API in the cortex-m crate
//!     unsafe {
//!         // enable TPIU and ITM
//!         cp.DCB.demcr.modify(|r| r | (1 << 24));
//!
//!         // prescaler
//!         let swo_freq = 2_000_000;
//!         cp.TPIU.acpr.write((clocks.sysclk().0 / swo_freq) - 1);
//!
//!         // SWO NRZ
//!         cp.TPIU.sppr.write(2);
//!
//!         cp.TPIU.ffcr.modify(|r| r & !(1 << 1));
//!
//!         // STM32 specific: enable tracing in the DBGMCU_CR register
//!         const DBGMCU_CR: *mut u32 = 0xe0042004 as *mut u32;
//!         let r = ptr::read_volatile(DBGMCU_CR);
//!         ptr::write_volatile(DBGMCU_CR, r | (1 << 5));
//!
//!         // unlock the ITM
//!         cp.ITM.lar.write(0xC5ACCE55);
//!
//!         cp.ITM.tcr.write(
//!             (0b000001 << 16) | // TraceBusID
//!             (1 << 3) | // enable SWO output
//!             (1 << 0), // enable the ITM
//!         );
//!
//!         // enable stimulus port 0
//!         cp.ITM.ter[0].write(1);
//!     }
//!
//!     let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);
//!     let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);
//!     let mut gpioe = dp.GPIOE.split(&mut rcc.ahb);
//!
//!     let mut nss = gpioe
//!         .pe3
//!         .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
//!     nss.set_high();
//!     let mut led = gpioe
//!         .pe9
//!         .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
//!
//!     let sck = gpioa.pa5.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!     let miso = gpioa.pa6.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!     let mosi = gpioa.pa7.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!
//!     let spi = Spi::spi1(
//!         dp.SPI1,
//!         (sck, miso, mosi),
//!         l3gd20::MODE,
//!         1.mhz(),
//!         clocks,
//!         &mut rcc.apb2,
//!     );
//!
//!     let mut l3gd20 = L3gd20::new(spi, nss).unwrap();
//!
//!     l3gd20.set_odr(Odr::Hz380).unwrap();
//!
//!     let scl = gpiob.pb6.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
//!     let sda = gpiob.pb7.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
//!
//!     let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 400.khz(), clocks, &mut rcc.apb1);
//!
//!     let mut lsm303dlhc = Lsm303dlhc::new(i2c).unwrap();
//!
//!     lsm303dlhc.accel_odr(AccelOdr::Hz400).unwrap();
//!     lsm303dlhc.mag_odr(MagOdr::Hz220).unwrap();
//!
//!     let mut timer = Timer::tim2(dp.TIM2, 380.hz(), clocks, &mut rcc.apb1);
//!
//!     // Calibrate the gyroscope
//!     let mut ar_bias_x = 0;
//!     let mut ar_bias_y = 0;
//!     let mut ar_bias_z = 0;
//!     for _ in 0..NSAMPLES {
//!         block!(timer.wait()).unwrap();
//!
//!         let ar = l3gd20.gyro().unwrap();
//!
//!         ar_bias_x += i32(ar.x);
//!         ar_bias_y += i32(ar.y);
//!         ar_bias_z += i32(ar.z);
//!     }
//!     let ar_bias_x = (ar_bias_x / NSAMPLES) as i16;
//!     let ar_bias_y = (ar_bias_y / NSAMPLES) as i16;
//!     let ar_bias_z = (ar_bias_z / NSAMPLES) as i16;
//!
//!     // Turn on the LED after calibrating the gyroscope
//!     led.set_high();
//!
//!     let mut marg = Marg::new(BETA, 1. / f32(SAMPLE_FREQ));
//!     let mut timer = Timer::tim2(timer.free(), SAMPLE_FREQ.hz(), clocks, &mut rcc.apb1);
//!
//!     let mut tx_buf: Aligned<u32, [u8; 18]> = Aligned([0; 18]);
//!     loop {
//!         block!(timer.wait()).unwrap();
//!
//!         let m = lsm303dlhc.mag().unwrap();
//!         let ar = l3gd20.gyro().unwrap();
//!         let g = lsm303dlhc.accel().unwrap();
//!
//!         let m_x = (f32(m.x) - M_BIAS_X) / M_SCALE_X;
//!         let m_y = (f32(m.y) - M_BIAS_Y) / M_SCALE_Y;
//!         let m_z = (f32(m.z) - M_BIAS_Z) / M_SCALE_Z;
//!
//!         // Fix the X Y Z components of the magnetometer so they match the gyro axes
//!         let m = F32x3 {
//!             x: m_y,
//!             y: -m_x,
//!             z: m_z,
//!         };
//!
//!         let ar_x = f32(ar.x - ar_bias_x) * K_AR;
//!         let ar_y = f32(ar.y - ar_bias_y) * K_AR;
//!         let ar_z = f32(ar.z - ar_bias_z) * K_AR;
//!         let ar = F32x3 {
//!             x: ar_x,
//!             y: ar_y,
//!             z: ar_z,
//!         };
//!
//!         // Fix the X Y Z components of the accelerometer so they match the gyro axes
//!         let g_x = f32(g.x) * K_G;
//!         let g_y = f32(g.y) * K_G;
//!         let g_z = f32(g.z) * K_G;
//!         let g = F32x3 {
//!             x: g_y,
//!             y: -g_x,
//!             z: g_z,
//!         };
//!
//!         // Run the filter
//!         let quat = marg.update(m, ar, g);
//!
//!         // Serialize the quaternion
//!         let mut start = 0;
//!         let mut buf = [0; 16];
//!         LE::write_f32(&mut buf[start..start + 4], quat.0);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.1);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.2);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.3);
//!         // start += 4;
//!
//!         // Log data
//!         cobs::encode(&buf, &mut tx_buf.array);
//!
//!         itm::write_aligned(&mut cp.ITM.stim[0], &tx_buf);
//!     }
//! }
//! ```
// Auto-generated. Do not modify.
<|endoftext|>


<commit_before>use libusb::*;
use std::unstable::intrinsics;
use std::libc::{c_int, c_void, size_t, malloc, free};
use std::vec;
use std::ptr::{to_mut_unsafe_ptr};
use std::result::Result;
use std::iterator::IteratorUtil;
use std::task;
use std::comm::{PortOne, ChanOne, SharedChan, stream, oneshot};
use std::cast::transmute;
use std::sys::size_of;

use std::unstable::sync::UnsafeAtomicRcBox;
use std::unstable::atomics::{AtomicInt, SeqCst};

pub struct ContextData {
	priv ctx: *mut libusb_context,
	priv open_device_count: AtomicInt
}

impl Drop for ContextData {
	fn drop(&self) {
		unsafe {
			assert!(self.open_device_count.load(SeqCst) == 0);
			// TODO: make sure backend thread is dead if the last device just closed
			libusb_exit(self.ctx);
		}
	}
}

pub struct Context {
	priv box: UnsafeAtomicRcBox<ContextData>
}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = intrinsics::init();
			let r = libusb_init(&mut ctx);

			Context{
				box: UnsafeAtomicRcBox::new(ContextData{
					ctx: ctx,
					open_device_count: AtomicInt::new(0)
				})
			}
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		unsafe{
			(*self.box.get()).ctx
		}
	}

	pub fn setDebug(&self, level: int) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn listDevices(&self) -> ~[Device] {
		unsafe{
			let mut list: *mut *mut libusb_device = intrinsics::init();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let r = vec::raw::mut_buf_as_slice(list, num_devices as uint, |l|{
				l.iter().transform(|i| Device{dev: *i, ctx: (*self).clone()}).collect()
			});

			libusb_free_device_list(list, 0);
			r
		}
	}

	pub fn find_by_vid_pid(&self, vid: uint, pid: uint) -> Option<Device> {
		self.listDevices().consume_iter().find_(|d| {
			let desc = d.descriptor();
			desc.idVendor as uint == vid && desc.idProduct as uint == pid
		})
	}

	priv fn device_opened(&self) {
		let count = unsafe { &mut (*self.box.get()).open_device_count };
		let old_count = count.fetch_add(1, SeqCst);

		if old_count == 0 {
			let tbox = self.box.clone();

			do task::spawn_sched(task::SingleThreaded) {
				unsafe {
					let ctx = (*tbox.get()).ctx;
					let count = &(*tbox.get()).open_device_count;

					while (count.load(SeqCst) > 0) {
						libusb_handle_events(ctx);
					}
				}
			}
		}
	}

	priv fn device_closed(&self) {
		let count = unsafe { &mut (*self.box.get()).open_device_count };
		count.fetch_sub(1, SeqCst);
	}
}

extern fn rust_usb_callback(transfer: *mut libusb_transfer) {
	unsafe {
		let chan: ~ChanOne<()> = transmute((*transfer).user_data);
		chan.send(());
	}
}

struct TH {
	t: *mut libusb_transfer,
	c: SharedChan<*mut libusb_transfer>,
}

impl Drop for TH{
	fn drop(&self) {
		unsafe {
			free((*self.t).buffer as *c_void);
			libusb_free_transfer(self.t);
		}
	}
}

extern fn rust_usb_stream_callback(transfer: *mut libusb_transfer) {
	unsafe {
		let chan: &SharedChan<*mut libusb_transfer> = transmute((*transfer).user_data);
		chan.send(transfer);
	}
}

impl Clone for Context{
	fn clone(&self) -> Context{
		Context{box: self.box.clone()}
	}
}

pub struct Device {
	priv dev: *mut libusb_device,
	ctx: Context
}

impl Device {
	pub fn descriptor(&self) -> ~libusb_device_descriptor {
		unsafe{
			let mut d: ~libusb_device_descriptor = ~intrinsics::uninit();
			libusb_get_device_descriptor(self.dev, to_mut_unsafe_ptr(d));
			d
		}
	}

	pub fn bus(&self) -> int {
		unsafe {
			libusb_get_bus_number(self.dev) as int
		}
	}

	pub fn address(&self) -> int {
		unsafe {
			libusb_get_device_address(self.dev) as int
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = intrinsics::uninit();
			let r = libusb_open(self.dev, &mut handle);
			if (r == 0){
				self.ctx.device_opened();
				Ok(DeviceHandle {
					box: UnsafeAtomicRcBox::new(DeviceHandleData {
						dev: handle,
						ctx: self.ctx.clone()
					})
				})
			}else{
				Err(r as int)
			}
		}
	}
}

impl Drop for Device {
	fn drop(&self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl Clone for Device {
	fn clone(&self) -> Device {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{dev: self.dev, ctx: self.ctx.clone()}
	}
}

struct DeviceHandleData{
	priv dev: *mut libusb_device_handle,
	priv ctx: Context
}

impl Drop for DeviceHandleData {
	fn drop(&self) {
		unsafe {
			self.ctx.device_closed();
			libusb_close(self.dev);
		}
	}
}

pub struct DeviceHandle {
	priv box: UnsafeAtomicRcBox<DeviceHandleData>
}

impl DeviceHandle {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		unsafe {
			(*self.box.get()).dev
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: uint,
		buffer: *mut u8) -> (libusb_transfer_status, uint) {

		let (port, chan): (PortOne<()>, ChanOne<()>) = oneshot();

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = 0;
		(*t).length = length as i32;
		(*t).callback = rust_usb_callback;
		(*t).user_data = transmute(~chan);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);
		port.recv();
		let r = ((*t).status, (*t).actual_length as uint);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint
			) -> Result<~[u8], libusb_transfer_status> {
		let mut buf: ~[u8] = vec::from_elem(size, 0u8);
		unsafe {
			let ptr = vec::raw::to_mut_ptr(buf);
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self, endpoint: u8, transfer_type: libusb_transfer_type, buf: &[u8]) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = vec::raw::to_ptr(buf) as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: uint) -> Result<~[u8], libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length as uint;
		let mut buf: ~[u8] = vec::from_elem(total_length, 0u8);

		unsafe{
			let ptr = fill_setup_buf(buf, bmRequestType, bRequest, wValue, wIndex, length);

			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf.slice(setup_length, setup_length+actual_length).to_owned())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8]) -> Result<(), libusb_transfer_status> {
		unsafe {
			let mut setup_buf = vec::from_elem(size_of::<libusb_control_setup>(), 0u8);
			fill_setup_buf(setup_buf, bmRequestType, bRequest, wValue, wIndex, buf.len());
			self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, setup_buf+buf)
		}
	}

	priv unsafe fn stream_transfers(&self, endpoint: u8,
			transfer_type: libusb_transfer_type, size: uint,
			num_transfers: uint) -> (Port<*mut libusb_transfer>, ~[TH]) {

		let (port, chan) = stream::<*mut libusb_transfer>();
		let sc = SharedChan::new(chan);

		let transfers = do vec::from_fn(num_transfers) |_| { TH {
			t: libusb_alloc_transfer(0),
			c: sc.clone(),
		}};

		for th in transfers.iter() {
			(*th.t).dev_handle = self.ptr();
			(*th.t).endpoint = endpoint;
			(*th.t).transfer_type = transfer_type as u8;
			(*th.t).timeout = 0;
			(*th.t).length = size as i32;
			(*th.t).callback = rust_usb_stream_callback;
			(*th.t).buffer = malloc(size as size_t) as *mut u8;
			(*th.t).user_data = transmute(&th.c);
		}

		return (port, transfers);
	}

	pub fn read_stream(&self, endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint, mut num_transfers: uint, cb: &fn(Result<&[u8], libusb_transfer_status>) -> bool) {

		unsafe {
			let mut running = true;
			let (port, transfers) = self.stream_transfers(
				endpoint, transfer_type, size, num_transfers);

			for th in transfers.iter() {
				libusb_submit_transfer(th.t);
			}

			while (num_transfers > 0) {
				let transfer: *mut libusb_transfer = port.recv();

				if ((*transfer).status == LIBUSB_TRANSFER_COMPLETED) {
					do vec::raw::buf_as_slice((*transfer).buffer as *u8, size) |b| {
						running &= cb(Ok(b))
					}
				} else {
					running = false;
					running &= cb(Err((*transfer).status));
				}

				if (running) {
					let r = libusb_submit_transfer(transfer);
					assert!(r == 0);
				} else {
					num_transfers -= 1;
				}
			}
		}
	}

	pub fn write_stream(&self, endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint, num_transfers: uint, cb: &fn(Result<(&mut[u8]), libusb_transfer_status>) -> bool) {

		unsafe {
			let mut running = true;
			let mut running_transfers = 0;
			let (port, transfers) = self.stream_transfers(
				endpoint, transfer_type, size, num_transfers);

			for th in transfers.iter() {
				do vec::raw::mut_buf_as_slice((*th.t).buffer, size) |b| {
					running &= cb(Ok(b));
				}
				if running {
					libusb_submit_transfer(th.t);
					running_transfers += 1;
				} else {
					break;
				}
			}

			while (running_transfers > 0) {
				let transfer: *mut libusb_transfer = port.recv();

				if ((*transfer).status == LIBUSB_TRANSFER_COMPLETED) {
					do vec::raw::mut_buf_as_slice((*transfer).buffer, size) |b| {
						running &= cb(Ok(b))
					}
				} else {
					running = false;
					running &= cb(Err((*transfer).status));
				}

				if (running) {
					let r = libusb_submit_transfer(transfer);
					assert!(r == 0);
				} else {
					running_transfers -= 1;
				}
			}
		}
	}
}

unsafe fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: uint) -> *mut u8 {
	let ptr = vec::raw::to_mut_ptr(buf);
	let setup = ptr as *mut libusb_control_setup;

	// TODO: these are always little-endian
	(*setup).bmRequestType = bmRequestType;
	(*setup).bRequest = bRequest;
	(*setup).wValue = wValue;
	(*setup).wIndex = wIndex;
	(*setup).wLength = length as u16;

	return ptr;
}

impl Clone for DeviceHandle {
	fn clone(&self) -> DeviceHandle {
		DeviceHandle{box: self.box.clone()}
	}
}
<commit_msg>Update for latest rustc<commit_after>use libusb::*;
use std::unstable::intrinsics;
use std::libc::{c_int, c_void, size_t, malloc, free};
use std::vec;
use std::ptr::{to_mut_unsafe_ptr};
use std::result::Result;
use std::task;
use std::comm::{PortOne, ChanOne, SharedChan, stream, oneshot};
use std::cast::transmute;
use std::sys::size_of;

use std::unstable::sync::UnsafeAtomicRcBox;
use std::unstable::atomics::{AtomicInt, SeqCst};

pub struct ContextData {
	priv ctx: *mut libusb_context,
	priv open_device_count: AtomicInt
}

impl Drop for ContextData {
	fn drop(&self) {
		unsafe {
			assert!(self.open_device_count.load(SeqCst) == 0);
			// TODO: make sure backend thread is dead if the last device just closed
			libusb_exit(self.ctx);
		}
	}
}

pub struct Context {
	priv box: UnsafeAtomicRcBox<ContextData>
}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = intrinsics::init();
			let r = libusb_init(&mut ctx);

			Context{
				box: UnsafeAtomicRcBox::new(ContextData{
					ctx: ctx,
					open_device_count: AtomicInt::new(0)
				})
			}
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		unsafe{
			(*self.box.get()).ctx
		}
	}

	pub fn setDebug(&self, level: int) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn listDevices(&self) -> ~[Device] {
		unsafe{
			let mut list: *mut *mut libusb_device = intrinsics::init();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let r = vec::raw::mut_buf_as_slice(list, num_devices as uint, |l|{
				l.iter().map(|i| Device{dev: *i, ctx: (*self).clone()}).collect()
			});

			libusb_free_device_list(list, 0);
			r
		}
	}

	pub fn find_by_vid_pid(&self, vid: uint, pid: uint) -> Option<Device> {
		self.listDevices().move_iter().find(|d| {
			let desc = d.descriptor();
			desc.idVendor as uint == vid && desc.idProduct as uint == pid
		})
	}

	fn device_opened(&self) {
		let count = unsafe { &mut (*self.box.get()).open_device_count };
		let old_count = count.fetch_add(1, SeqCst);

		if old_count == 0 {
			let tbox = self.box.clone();

			do task::spawn_sched(task::SingleThreaded) {
				unsafe {
					let ctx = (*tbox.get()).ctx;
					let count = &(*tbox.get()).open_device_count;

					while (count.load(SeqCst) > 0) {
						libusb_handle_events(ctx);
					}
				}
			}
		}
	}

	fn device_closed(&self) {
		let count = unsafe { &mut (*self.box.get()).open_device_count };
		count.fetch_sub(1, SeqCst);
	}
}

extern fn rust_usb_callback(transfer: *mut libusb_transfer) {
	unsafe {
		let chan: ~ChanOne<()> = transmute((*transfer).user_data);
		chan.send(());
	}
}

struct TH {
	t: *mut libusb_transfer,
	c: SharedChan<*mut libusb_transfer>,
}

impl Drop for TH{
	fn drop(&self) {
		unsafe {
			free((*self.t).buffer as *c_void);
			libusb_free_transfer(self.t);
		}
	}
}

extern fn rust_usb_stream_callback(transfer: *mut libusb_transfer) {
	unsafe {
		let chan: &SharedChan<*mut libusb_transfer> = transmute((*transfer).user_data);
		chan.send(transfer);
	}
}

impl Clone for Context{
	fn clone(&self) -> Context{
		Context{box: self.box.clone()}
	}
}

pub struct Device {
	priv dev: *mut libusb_device,
	ctx: Context
}

impl Device {
	pub fn descriptor(&self) -> ~libusb_device_descriptor {
		unsafe{
			let mut d: ~libusb_device_descriptor = ~intrinsics::uninit();
			libusb_get_device_descriptor(self.dev, to_mut_unsafe_ptr(d));
			d
		}
	}

	pub fn bus(&self) -> int {
		unsafe {
			libusb_get_bus_number(self.dev) as int
		}
	}

	pub fn address(&self) -> int {
		unsafe {
			libusb_get_device_address(self.dev) as int
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = intrinsics::uninit();
			let r = libusb_open(self.dev, &mut handle);
			if (r == 0){
				self.ctx.device_opened();
				Ok(DeviceHandle {
					box: UnsafeAtomicRcBox::new(DeviceHandleData {
						dev: handle,
						ctx: self.ctx.clone()
					})
				})
			}else{
				Err(r as int)
			}
		}
	}
}

impl Drop for Device {
	fn drop(&self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl Clone for Device {
	fn clone(&self) -> Device {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{dev: self.dev, ctx: self.ctx.clone()}
	}
}

struct DeviceHandleData{
	priv dev: *mut libusb_device_handle,
	priv ctx: Context
}

impl Drop for DeviceHandleData {
	fn drop(&self) {
		unsafe {
			self.ctx.device_closed();
			libusb_close(self.dev);
		}
	}
}

pub struct DeviceHandle {
	priv box: UnsafeAtomicRcBox<DeviceHandleData>
}

impl DeviceHandle {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		unsafe {
			(*self.box.get()).dev
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: uint,
		buffer: *mut u8) -> (libusb_transfer_status, uint) {

		let (port, chan): (PortOne<()>, ChanOne<()>) = oneshot();

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = 0;
		(*t).length = length as i32;
		(*t).callback = rust_usb_callback;
		(*t).user_data = transmute(~chan);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);
		port.recv();
		let r = ((*t).status, (*t).actual_length as uint);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint
			) -> Result<~[u8], libusb_transfer_status> {
		let mut buf: ~[u8] = vec::from_elem(size, 0u8);
		unsafe {
			let ptr = vec::raw::to_mut_ptr(buf);
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self, endpoint: u8, transfer_type: libusb_transfer_type, buf: &[u8]) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = vec::raw::to_ptr(buf) as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: uint) -> Result<~[u8], libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length as uint;
		let mut buf: ~[u8] = vec::from_elem(total_length, 0u8);

		unsafe{
			let ptr = fill_setup_buf(buf, bmRequestType, bRequest, wValue, wIndex, length);

			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf.slice(setup_length, setup_length+actual_length).to_owned())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8]) -> Result<(), libusb_transfer_status> {
		unsafe {
			let mut setup_buf = vec::from_elem(size_of::<libusb_control_setup>(), 0u8);
			fill_setup_buf(setup_buf, bmRequestType, bRequest, wValue, wIndex, buf.len());
			self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, setup_buf+buf)
		}
	}

	unsafe fn stream_transfers(&self, endpoint: u8,
			transfer_type: libusb_transfer_type, size: uint,
			num_transfers: uint) -> (Port<*mut libusb_transfer>, ~[TH]) {

		let (port, chan) = stream::<*mut libusb_transfer>();
		let sc = SharedChan::new(chan);

		let transfers = do vec::from_fn(num_transfers) |_| { TH {
			t: libusb_alloc_transfer(0),
			c: sc.clone(),
		}};

		for th in transfers.iter() {
			(*th.t).dev_handle = self.ptr();
			(*th.t).endpoint = endpoint;
			(*th.t).transfer_type = transfer_type as u8;
			(*th.t).timeout = 0;
			(*th.t).length = size as i32;
			(*th.t).callback = rust_usb_stream_callback;
			(*th.t).buffer = malloc(size as size_t) as *mut u8;
			(*th.t).user_data = transmute(&th.c);
		}

		return (port, transfers);
	}

	pub fn read_stream(&self, endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint, mut num_transfers: uint, cb: &fn(Result<&[u8], libusb_transfer_status>) -> bool) {

		unsafe {
			let mut running = true;
			let (port, transfers) = self.stream_transfers(
				endpoint, transfer_type, size, num_transfers);

			for th in transfers.iter() {
				libusb_submit_transfer(th.t);
			}

			while (num_transfers > 0) {
				let transfer: *mut libusb_transfer = port.recv();

				if ((*transfer).status == LIBUSB_TRANSFER_COMPLETED) {
					do vec::raw::buf_as_slice((*transfer).buffer as *u8, size) |b| {
						running &= cb(Ok(b))
					}
				} else {
					running = false;
					running &= cb(Err((*transfer).status));
				}

				if (running) {
					let r = libusb_submit_transfer(transfer);
					assert!(r == 0);
				} else {
					num_transfers -= 1;
				}
			}
		}
	}

	pub fn write_stream(&self, endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint, num_transfers: uint, cb: &fn(Result<(&mut[u8]), libusb_transfer_status>) -> bool) {

		unsafe {
			let mut running = true;
			let mut running_transfers = 0;
			let (port, transfers) = self.stream_transfers(
				endpoint, transfer_type, size, num_transfers);

			for th in transfers.iter() {
				do vec::raw::mut_buf_as_slice((*th.t).buffer, size) |b| {
					running &= cb(Ok(b));
				}
				if running {
					libusb_submit_transfer(th.t);
					running_transfers += 1;
				} else {
					break;
				}
			}

			while (running_transfers > 0) {
				let transfer: *mut libusb_transfer = port.recv();

				if ((*transfer).status == LIBUSB_TRANSFER_COMPLETED) {
					do vec::raw::mut_buf_as_slice((*transfer).buffer, size) |b| {
						running &= cb(Ok(b))
					}
				} else {
					running = false;
					running &= cb(Err((*transfer).status));
				}

				if (running) {
					let r = libusb_submit_transfer(transfer);
					assert!(r == 0);
				} else {
					running_transfers -= 1;
				}
			}
		}
	}
}

unsafe fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: uint) -> *mut u8 {
	let ptr = vec::raw::to_mut_ptr(buf);
	let setup = ptr as *mut libusb_control_setup;

	// TODO: these are always little-endian
	(*setup).bmRequestType = bmRequestType;
	(*setup).bRequest = bRequest;
	(*setup).wValue = wValue;
	(*setup).wIndex = wIndex;
	(*setup).wLength = length as u16;

	return ptr;
}

impl Clone for DeviceHandle {
	fn clone(&self) -> DeviceHandle {
		DeviceHandle{box: self.box.clone()}
	}
}
<|endoftext|>


<commit_before>use crate::consts::{constant, Constant};
use crate::utils::sugg::Sugg;
use crate::utils::{span_lint, span_lint_and_then};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for incompatible bit masks in comparisons.
    ///
    /// The formula for detecting if an expression of the type `_ <bit_op> m
    /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
    /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
    /// table:
    ///
    /// |Comparison  |Bit Op|Example     |is always|Formula               |
    /// |------------|------|------------|---------|----------------------|
    /// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
    /// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
    /// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
    /// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
    /// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
    /// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
    ///
    /// **Why is this bad?** If the bits that the comparison cares about are always
    /// set to zero or one by the bit mask, the comparison is constant `true` or
    /// `false` (depending on mask, compared value, and operators).
    ///
    /// So the code is actively misleading, and the only reason someone would write
    /// this intentionally is to win an underhanded Rust contest or create a
    /// test-case for this lint.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if (x & 1 == 2) { }
    /// ```
    pub BAD_BIT_MASK,
    correctness,
    "expressions of the form `_ & mask == select` that will only ever return `true` or `false`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for bit masks in comparisons which can be removed
    /// without changing the outcome. The basic structure can be seen in the
    /// following table:
    ///
    /// |Comparison| Bit Op  |Example    |equals |
    /// |----------|---------|-----------|-------|
    /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|
    /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|
    ///
    /// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
    /// but still a bit misleading, because the bit mask is ineffective.
    ///
    /// **Known problems:** False negatives: This lint will only match instances
    /// where we have figured out the math (which is for a power-of-two compared
    /// value). This means things like `x | 1 >= 7` (which would be better written
    /// as `x >= 6`) will not be reported (but bit masks like this are fairly
    /// uncommon).
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if (x | 1 > 3) {  }
    /// ```
    pub INEFFECTIVE_BIT_MASK,
    correctness,
    "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for bit masks that can be replaced by a call
    /// to `trailing_zeros`
    ///
    /// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15
    /// == 0`
    ///
    /// **Known problems:** llvm generates better code for `x & 15 == 0` on x86
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if x & 0x1111 == 0 { }
    /// ```
    pub VERBOSE_BIT_MASK,
    style,
    "expressions where a bit mask is less readable than the corresponding method call"
}

#[derive(Copy, Clone)]
pub struct BitMask {
    verbose_bit_mask_threshold: u64,
}

impl BitMask {
    #[must_use]
    pub fn new(verbose_bit_mask_threshold: u64) -> Self {
        Self {
            verbose_bit_mask_threshold,
        }
    }
}

impl_lint_pass!(BitMask => [BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        if let ExprKind::Binary(cmp, left, right) = &e.kind {
            if cmp.node.is_comparison() {
                if let Some(cmp_opt) = fetch_int_literal(cx, right) {
                    check_compare(cx, left, cmp.node, cmp_opt, e.span)
                } else if let Some(cmp_val) = fetch_int_literal(cx, left) {
                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span)
                }
            }
        }
        if_chain! {
            if let ExprKind::Binary(op, left, right) = &e.kind;
            if BinOpKind::Eq == op.node;
            if let ExprKind::Binary(op1, left1, right1) = &left.kind;
            if BinOpKind::BitAnd == op1.node;
            if let ExprKind::Lit(lit) = &right1.kind;
            if let LitKind::Int(n, _) = lit.node;
            if let ExprKind::Lit(lit1) = &right.kind;
            if let LitKind::Int(0, _) = lit1.node;
            if n.leading_zeros() == n.count_zeros();
            if n > u128::from(self.verbose_bit_mask_threshold);
            then {
                span_lint_and_then(cx,
                                   VERBOSE_BIT_MASK,
                                   e.span,
                                   "bit mask could be simplified with a call to `trailing_zeros`",
                                   |db| {
                    let sugg = Sugg::hir(cx, left1, "...").maybe_par();
                    db.span_suggestion(
                        e.span,
                        "try",
                        format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()),
                        Applicability::MaybeIncorrect,
                    );
                });
            }
        }
    }
}

#[must_use]
fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
    match cmp {
        BinOpKind::Eq => BinOpKind::Eq,
        BinOpKind::Ne => BinOpKind::Ne,
        BinOpKind::Lt => BinOpKind::Gt,
        BinOpKind::Gt => BinOpKind::Lt,
        BinOpKind::Le => BinOpKind::Ge,
        BinOpKind::Ge => BinOpKind::Le,
        _ => BinOpKind::Or, // Dummy
    }
}

fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp_value: u128, span: Span) {
    if let ExprKind::Binary(op, left, right) = &bit_op.kind {
        if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
            return;
        }
        fetch_int_literal(cx, right)
            .or_else(|| fetch_int_literal(cx, left))
            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span))
    }
}

#[allow(clippy::too_many_lines)]
fn check_bit_mask(
    cx: &LateContext<'_, '_>,
    bit_op: BinOpKind,
    cmp_op: BinOpKind,
    mask_value: u128,
    cmp_value: u128,
    span: Span,
) {
    match cmp_op {
        BinOpKind::Eq | BinOpKind::Ne => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value & cmp_value != cmp_value {
                    if cmp_value != 0 {
                        span_lint(
                            cx,
                            BAD_BIT_MASK,
                            span,
                            &format!(
                                "incompatible bit mask: `_ & {}` can never be equal to `{}`",
                                mask_value, cmp_value
                            ),
                        );
                    }
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value | cmp_value != cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` can never be equal to `{}`",
                            mask_value, cmp_value
                        ),
                    );
                }
            },
            _ => (),
        },
        BinOpKind::Lt | BinOpKind::Ge => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value < cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ & {}` will always be lower than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value >= cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` will never be lower than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else {
                    check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
                }
            },
            BinOpKind::BitXor => check_ineffective_lt(cx, span, mask_value, cmp_value, "^"),
            _ => (),
        },
        BinOpKind::Le | BinOpKind::Gt => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value <= cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ & {}` will never be higher than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value > cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` will always be higher than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else {
                    check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
                }
            },
            BinOpKind::BitXor => check_ineffective_gt(cx, span, mask_value, cmp_value, "^"),
            _ => (),
        },
        _ => (),
    }
}

fn check_ineffective_lt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) {
    if c.is_power_of_two() && m < c {
        span_lint(
            cx,
            INEFFECTIVE_BIT_MASK,
            span,
            &format!(
                "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
                op, m, c
            ),
        );
    }
}

fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) {
    if (c + 1).is_power_of_two() && m <= c {
        span_lint(
            cx,
            INEFFECTIVE_BIT_MASK,
            span,
            &format!(
                "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
                op, m, c
            ),
        );
    }
}

fn fetch_int_literal(cx: &LateContext<'_, '_>, lit: &Expr<'_>) -> Option<u128> {
    match constant(cx, cx.tables, lit)?.0 {
        Constant::Int(n) => Some(n),
        _ => None,
    }
}
<commit_msg>verbose_bit_mask: fix bit mask used in docs<commit_after>use crate::consts::{constant, Constant};
use crate::utils::sugg::Sugg;
use crate::utils::{span_lint, span_lint_and_then};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for incompatible bit masks in comparisons.
    ///
    /// The formula for detecting if an expression of the type `_ <bit_op> m
    /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
    /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
    /// table:
    ///
    /// |Comparison  |Bit Op|Example     |is always|Formula               |
    /// |------------|------|------------|---------|----------------------|
    /// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
    /// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
    /// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
    /// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
    /// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
    /// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
    ///
    /// **Why is this bad?** If the bits that the comparison cares about are always
    /// set to zero or one by the bit mask, the comparison is constant `true` or
    /// `false` (depending on mask, compared value, and operators).
    ///
    /// So the code is actively misleading, and the only reason someone would write
    /// this intentionally is to win an underhanded Rust contest or create a
    /// test-case for this lint.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if (x & 1 == 2) { }
    /// ```
    pub BAD_BIT_MASK,
    correctness,
    "expressions of the form `_ & mask == select` that will only ever return `true` or `false`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for bit masks in comparisons which can be removed
    /// without changing the outcome. The basic structure can be seen in the
    /// following table:
    ///
    /// |Comparison| Bit Op  |Example    |equals |
    /// |----------|---------|-----------|-------|
    /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|
    /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|
    ///
    /// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
    /// but still a bit misleading, because the bit mask is ineffective.
    ///
    /// **Known problems:** False negatives: This lint will only match instances
    /// where we have figured out the math (which is for a power-of-two compared
    /// value). This means things like `x | 1 >= 7` (which would be better written
    /// as `x >= 6`) will not be reported (but bit masks like this are fairly
    /// uncommon).
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if (x | 1 > 3) {  }
    /// ```
    pub INEFFECTIVE_BIT_MASK,
    correctness,
    "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for bit masks that can be replaced by a call
    /// to `trailing_zeros`
    ///
    /// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15
    /// == 0`
    ///
    /// **Known problems:** llvm generates better code for `x & 15 == 0` on x86
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if x & 0b1111 == 0 { }
    /// ```
    pub VERBOSE_BIT_MASK,
    style,
    "expressions where a bit mask is less readable than the corresponding method call"
}

#[derive(Copy, Clone)]
pub struct BitMask {
    verbose_bit_mask_threshold: u64,
}

impl BitMask {
    #[must_use]
    pub fn new(verbose_bit_mask_threshold: u64) -> Self {
        Self {
            verbose_bit_mask_threshold,
        }
    }
}

impl_lint_pass!(BitMask => [BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        if let ExprKind::Binary(cmp, left, right) = &e.kind {
            if cmp.node.is_comparison() {
                if let Some(cmp_opt) = fetch_int_literal(cx, right) {
                    check_compare(cx, left, cmp.node, cmp_opt, e.span)
                } else if let Some(cmp_val) = fetch_int_literal(cx, left) {
                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span)
                }
            }
        }
        if_chain! {
            if let ExprKind::Binary(op, left, right) = &e.kind;
            if BinOpKind::Eq == op.node;
            if let ExprKind::Binary(op1, left1, right1) = &left.kind;
            if BinOpKind::BitAnd == op1.node;
            if let ExprKind::Lit(lit) = &right1.kind;
            if let LitKind::Int(n, _) = lit.node;
            if let ExprKind::Lit(lit1) = &right.kind;
            if let LitKind::Int(0, _) = lit1.node;
            if n.leading_zeros() == n.count_zeros();
            if n > u128::from(self.verbose_bit_mask_threshold);
            then {
                span_lint_and_then(cx,
                                   VERBOSE_BIT_MASK,
                                   e.span,
                                   "bit mask could be simplified with a call to `trailing_zeros`",
                                   |db| {
                    let sugg = Sugg::hir(cx, left1, "...").maybe_par();
                    db.span_suggestion(
                        e.span,
                        "try",
                        format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()),
                        Applicability::MaybeIncorrect,
                    );
                });
            }
        }
    }
}

#[must_use]
fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
    match cmp {
        BinOpKind::Eq => BinOpKind::Eq,
        BinOpKind::Ne => BinOpKind::Ne,
        BinOpKind::Lt => BinOpKind::Gt,
        BinOpKind::Gt => BinOpKind::Lt,
        BinOpKind::Le => BinOpKind::Ge,
        BinOpKind::Ge => BinOpKind::Le,
        _ => BinOpKind::Or, // Dummy
    }
}

fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp_value: u128, span: Span) {
    if let ExprKind::Binary(op, left, right) = &bit_op.kind {
        if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
            return;
        }
        fetch_int_literal(cx, right)
            .or_else(|| fetch_int_literal(cx, left))
            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span))
    }
}

#[allow(clippy::too_many_lines)]
fn check_bit_mask(
    cx: &LateContext<'_, '_>,
    bit_op: BinOpKind,
    cmp_op: BinOpKind,
    mask_value: u128,
    cmp_value: u128,
    span: Span,
) {
    match cmp_op {
        BinOpKind::Eq | BinOpKind::Ne => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value & cmp_value != cmp_value {
                    if cmp_value != 0 {
                        span_lint(
                            cx,
                            BAD_BIT_MASK,
                            span,
                            &format!(
                                "incompatible bit mask: `_ & {}` can never be equal to `{}`",
                                mask_value, cmp_value
                            ),
                        );
                    }
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value | cmp_value != cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` can never be equal to `{}`",
                            mask_value, cmp_value
                        ),
                    );
                }
            },
            _ => (),
        },
        BinOpKind::Lt | BinOpKind::Ge => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value < cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ & {}` will always be lower than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value >= cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` will never be lower than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else {
                    check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
                }
            },
            BinOpKind::BitXor => check_ineffective_lt(cx, span, mask_value, cmp_value, "^"),
            _ => (),
        },
        BinOpKind::Le | BinOpKind::Gt => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value <= cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ & {}` will never be higher than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value > cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` will always be higher than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else {
                    check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
                }
            },
            BinOpKind::BitXor => check_ineffective_gt(cx, span, mask_value, cmp_value, "^"),
            _ => (),
        },
        _ => (),
    }
}

fn check_ineffective_lt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) {
    if c.is_power_of_two() && m < c {
        span_lint(
            cx,
            INEFFECTIVE_BIT_MASK,
            span,
            &format!(
                "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
                op, m, c
            ),
        );
    }
}

fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) {
    if (c + 1).is_power_of_two() && m <= c {
        span_lint(
            cx,
            INEFFECTIVE_BIT_MASK,
            span,
            &format!(
                "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
                op, m, c
            ),
        );
    }
}

fn fetch_int_literal(cx: &LateContext<'_, '_>, lit: &Expr<'_>) -> Option<u128> {
    match constant(cx, cx.tables, lit)?.0 {
        Constant::Int(n) => Some(n),
        _ => None,
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use aws_http::AwsErrorRetryPolicy;
use aws_hyper::{SdkError, SdkSuccess};
use aws_sdk_dynamodb::error::DescribeTableError;
use aws_sdk_dynamodb::input::DescribeTableInput;
use aws_sdk_dynamodb::model::{
    AttributeDefinition, AttributeValue, KeySchemaElement, KeyType, ProvisionedThroughput,
    ScalarAttributeType, Select, TableStatus,
};
use aws_sdk_dynamodb::operation::DescribeTable;
use aws_sdk_dynamodb::output::DescribeTableOutput;
use aws_sdk_dynamodb::{Client, Config, Error, Region, PKG_VERSION};
use aws_types::region;
use aws_types::region::ProvideRegion;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use smithy_http::operation::Operation;
use smithy_http::retry::ClassifyResponse;
use smithy_types::retry::RetryKind;
use std::io::{stdin, Read};
use std::time::Duration;
use std::{iter, process};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// Whether to run in interactive mode (you have to press return between operations)
    #[structopt(short, long)]
    interactive: bool,

    /// The AWS Region
    #[structopt(short, long)]
    region: Option<String>,

    /// Activate verbose mode
    #[structopt(short, long)]
    verbose: bool,
}

/// Create a random, n-length string
fn random_string(n: usize) -> String {
    let mut rng = thread_rng();
    iter::repeat(())
        .map(|()| rng.sample(Alphanumeric))
        .map(char::from)
        .take(n)
        .collect()
}

/// Create a new table. It's remotely possible the random table name exists.
async fn create_table(client: &Client, table: &str, key: &str) {
    let ad = AttributeDefinition::builder()
        .attribute_name(key)
        .attribute_type(ScalarAttributeType::S)
        .build();

    let ks = KeySchemaElement::builder()
        .attribute_name(key)
        .key_type(KeyType::Hash)
        .build();

    let pt = ProvisionedThroughput::builder()
        .read_capacity_units(10)
        .write_capacity_units(5)
        .build();

    match client
        .create_table()
        .table_name(table)
        .key_schema(ks)
        .attribute_definitions(ad)
        .provisioned_throughput(pt)
        .send()
        .await
    {
        Ok(_) => println!("Created the table."),
        Err(e) => {
            println!("Got an error creating the table:");
            println!("{}", e);
            process::exit(1);
        }
    }
}

/// For add_item and scan_item
#[derive(Clone)]
struct Item {
    table: String,
    key: String,
    value: String,
    first_name: String,
    last_name: String,
    age: String,
    utype: String,
}

/// Add an item to the table.
async fn add_item(client: &Client, item: Item) {
    let user_av = AttributeValue::S(item.value);
    let type_av = AttributeValue::S(item.utype);
    let age_av = AttributeValue::S(item.age);
    let first_av = AttributeValue::S(item.first_name);
    let last_av = AttributeValue::S(item.last_name);

    match client
        .put_item()
        .table_name(item.table)
        .item(item.key, user_av)
        .item("account_type", type_av)
        .item("age", age_av)
        .item("first_name", first_av)
        .item("last_name", last_av)
        .send()
        .await
    {
        Ok(_) => println!("Added item to or modified item in table."),
        Err(e) => {
            println!("Got an error adding item to table:");
            println!("{}", e);
            process::exit(1);
        }
    }
}

/// Query the table for an item matching the input values.
async fn query(client: &Client, item: Item) {
    let value = &item.value;
    let key = &item.key;
    let user_av = AttributeValue::S(value.to_string());

    match client
        .query()
        .table_name(item.table)
        .key_condition_expression("#key = :value".to_string())
        .expression_attribute_names("#key".to_string(), key.to_string())
        .expression_attribute_values(":value".to_string(), user_av)
        .select(Select::AllAttributes)
        .send()
        .await
    {
        Ok(resp) => {
            if resp.count > 0 {
                println!("Found a matching entry in table.");
            } else {
                println!("Did not find a match.");
            }
        }
        Err(e) => {
            println!("Got an error adding item to table:");
            println!("{}", e);
            process::exit(1);
        }
    }
}

/// Delete an item from the table.
async fn delete_item(client: &Client, table: &str, key: &str, value: &str) {
    let user_av = AttributeValue::S(String::from(value));
    match client
        .delete_item()
        .table_name(table)
        .key(key, user_av)
        .send()
        .await
    {
        Ok(_) => println!("Deleted the item."),
        Err(e) => {
            println!("Got an error trying to delete item:");
            println!("{}", e);
            process::exit(1);
        }
    }
}

/// Delete the table.
async fn delete_table(client: &Client, table: &str) {
    match client.delete_table().table_name(table).send().await {
        Ok(_) => println!("Deleted the table."),
        Err(e) => {
            println!("Got an error deleting table:");
            println!("{}", e);
            process::exit(1);
        }
    }
}

/// Hand-written waiter to retry every second until the table is out of `Creating` state
#[derive(Clone)]
struct WaitForReadyTable<R> {
    inner: R,
}

impl<R> ClassifyResponse<SdkSuccess<DescribeTableOutput>, SdkError<DescribeTableError>>
    for WaitForReadyTable<R>
where
    R: ClassifyResponse<SdkSuccess<DescribeTableOutput>, SdkError<DescribeTableError>>,
{
    fn classify(
        &self,
        response: Result<&SdkSuccess<DescribeTableOutput>, &SdkError<DescribeTableError>>,
    ) -> RetryKind {
        match self.inner.classify(response) {
            RetryKind::NotRetryable => (),
            other => return other,
        };
        match response {
            Ok(SdkSuccess { parsed, .. }) => {
                if parsed
                    .table
                    .as_ref()
                    .unwrap()
                    .table_status
                    .as_ref()
                    .unwrap()
                    == &TableStatus::Creating
                {
                    RetryKind::Explicit(Duration::from_secs(1))
                } else {
                    RetryKind::NotRetryable
                }
            }
            _ => RetryKind::NotRetryable,
        }
    }
}

/// Wait for the user to press Enter.
fn pause() {
    println!();
    println!("Press Enter to continue.");
    println!();
    stdin().read_exact(&mut [0]).unwrap();
}

/// Performs CRUD (create, read, update, delete) operations on a DynamoDB table and table item.
/// It creates a table, adds an item to the table, updates the item, deletes the item, and deletes the table.
/// The table name, primary key, and primary key value are all created as random strings.
///
/// # Arguments
///
/// * `[-i]` - Whether to pause between operations.
/// * `[-r REGION]` - The region in which the client is created.
///    If not supplied, uses the value of the **AWS_REGION** environment variable.
///    If the environment variable is not set, defaults to **us-west-2**.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt::init();
    let Opt {
        interactive,
        region,
        verbose,
    } = Opt::from_args();

    let region = region::ChainProvider::first_try(region.map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-west-2"));

    // Create 10-character random table name
    let table = random_string(10);

    // Create a 6-character random key name
    let key = random_string(6);

    // Create a 12-character random key value
    let value = random_string(12);

    // Specify first name, last name, age, and type
    let first_name = "DummyFirstName";
    let last_name = "DummyLastName";
    let age = "33";
    let utype = "standard_user";

    if verbose {
        println!("DynamoDB client version: {}", PKG_VERSION);
        println!(
            "Region:                 {}",
            region.region().unwrap().as_ref()
        );
        println!("Table:                   {}", table);
        println!("Key:                     {}", key);
        println!("Value:                   {}", value);

        println!();
    }

    let conf = Config::builder().region(region).build();
    let client = Client::from_conf(conf);

    /* Create table */
    println!();
    println!("Creating table.");
    create_table(&client, &table, &key).await;
    println!();

    println!("Waiting for table to be ready.");

    let raw_client = aws_hyper::Client::https();

    raw_client
        .call(wait_for_ready_table(&table, client.conf()))
        .await
        .expect("table should become ready");

    println!("Table is now ready to use");

    if interactive {
        pause();
    }

    println!();
    println!("Adding item to table.");

    let mut item = Item {
        table: table.clone(),
        key: key.clone(),
        value: value.clone(),
        first_name: first_name.to_string(),
        last_name: last_name.to_string(),
        age: age.to_string(),
        utype: utype.to_string(),
    };

    add_item(&client, item.clone()).await;

    println!();

    if interactive {
        pause();
    }

    item.age = "44".to_string();

    /* Update the item */
    println!("Modifying table item.");

    add_item(&client, item.clone()).await;
    println!();

    if interactive {
        pause();
    }

    /* Get item and compare it with the one we added */
    println!("Comparing table item to original value.");

    query(&client, item).await;
    println!();

    if interactive {
        pause();
    }

    /* Delete item */
    println!("Deleting item");
    delete_item(&client, &table, &key, &value).await;
    println!();

    if interactive {
        pause();
    }

    /* Delete table */
    println!("Deleting table");
    delete_table(&client, &table).await;
    println!();

    Ok(())
}

/// Construct a `DescribeTable` request with a policy to retry every second until the table
/// is ready
fn wait_for_ready_table(
    table_name: &str,
    conf: &Config,
) -> Operation<DescribeTable, WaitForReadyTable<AwsErrorRetryPolicy>> {
    let operation = DescribeTableInput::builder()
        .table_name(table_name)
        .build()
        .expect("valid input")
        .make_operation(&conf)
        .expect("valid operation");
    let waiting_policy = WaitForReadyTable {
        inner: operation.retry_policy().clone(),
    };
    operation.with_retry_policy(waiting_policy)
}
<commit_msg>Removed explicit check for existing table in DynamoDB crud code example<commit_after>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use aws_http::AwsErrorRetryPolicy;
use aws_hyper::{SdkError, SdkSuccess};
use aws_sdk_dynamodb::error::DescribeTableError;
use aws_sdk_dynamodb::input::DescribeTableInput;
use aws_sdk_dynamodb::model::{
    AttributeDefinition, AttributeValue, KeySchemaElement, KeyType, ProvisionedThroughput,
    ScalarAttributeType, Select, TableStatus,
};
use aws_sdk_dynamodb::operation::DescribeTable;
use aws_sdk_dynamodb::output::DescribeTableOutput;
use aws_sdk_dynamodb::{Client, Config, Error, Region, PKG_VERSION};
use aws_types::region;
use aws_types::region::ProvideRegion;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use smithy_http::operation::Operation;
use smithy_http::retry::ClassifyResponse;
use smithy_types::retry::RetryKind;
use std::io::{stdin, Read};
use std::time::Duration;
use std::{iter, process};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// Whether to run in interactive mode (you have to press return between operations)
    #[structopt(short, long)]
    interactive: bool,

    /// The AWS Region
    #[structopt(short, long)]
    region: Option<String>,

    /// Activate verbose mode
    #[structopt(short, long)]
    verbose: bool,
}

/// Create a random, n-length string
fn random_string(n: usize) -> String {
    let mut rng = thread_rng();
    iter::repeat(())
        .map(|()| rng.sample(Alphanumeric))
        .map(char::from)
        .take(n)
        .collect()
}

/// Create a new table.
async fn make_table(
    client: &Client,
    table: &str,
    key: &str,
) -> Result<(), aws_hyper::SdkError<aws_sdk_dynamodb::error::CreateTableError>> {
    let ad = AttributeDefinition::builder()
        .attribute_name(key)
        .attribute_type(ScalarAttributeType::S)
        .build();

    let ks = KeySchemaElement::builder()
        .attribute_name(key)
        .key_type(KeyType::Hash)
        .build();

    let pt = ProvisionedThroughput::builder()
        .read_capacity_units(10)
        .write_capacity_units(5)
        .build();

    match client
        .create_table()
        .table_name(table)
        .key_schema(ks)
        .attribute_definitions(ad)
        .provisioned_throughput(pt)
        .send()
        .await
    {
        Ok(_) => Ok(()),
        Err(e) => Err(e),
    }
}

/// For add_item and query_item
#[derive(Clone)]
struct Item {
    table: String,
    key: String,
    value: String,
    first_name: String,
    last_name: String,
    age: String,
    utype: String,
}

/// Add an item to the table.
async fn add_item(
    client: &Client,
    item: Item,
) -> Result<(), SdkError<aws_sdk_dynamodb::error::PutItemError>> {
    let user_av = AttributeValue::S(item.value);
    let type_av = AttributeValue::S(item.utype);
    let age_av = AttributeValue::S(item.age);
    let first_av = AttributeValue::S(item.first_name);
    let last_av = AttributeValue::S(item.last_name);

    match client
        .put_item()
        .table_name(item.table)
        .item(item.key, user_av)
        .item("account_type", type_av)
        .item("age", age_av)
        .item("first_name", first_av)
        .item("last_name", last_av)
        .send()
        .await
    {
        Ok(_) => Ok(()),
        Err(e) => Err(e),
    }
}

/// Query the table for an item matching the input values.
/// Returns true if the item is found; otherwise false.
async fn query_item(client: &Client, item: Item) -> bool {
    let value = &item.value;
    let key = &item.key;
    let user_av = AttributeValue::S(value.to_string());

    match client
        .query()
        .table_name(item.table)
        .key_condition_expression("#key = :value".to_string())
        .expression_attribute_names("#key".to_string(), key.to_string())
        .expression_attribute_values(":value".to_string(), user_av)
        .select(Select::AllAttributes)
        .send()
        .await
    {
        Ok(resp) => {
            if resp.count > 0 {
                println!("Found a matching entry in the table:");
                println!("{:?}", resp.items.unwrap_or_default().pop());
                true
            } else {
                println!("Did not find a match.");
                false
            }
        }
        Err(e) => {
            println!("Got an error querying table:");
            println!("{}", e);
            process::exit(1);
        }
    }
}

/// Hand-written waiter to retry every second until the table is out of `Creating` state
#[derive(Clone)]
struct WaitForReadyTable<R> {
    inner: R,
}

impl<R> ClassifyResponse<SdkSuccess<DescribeTableOutput>, SdkError<DescribeTableError>>
    for WaitForReadyTable<R>
where
    R: ClassifyResponse<SdkSuccess<DescribeTableOutput>, SdkError<DescribeTableError>>,
{
    fn classify(
        &self,
        response: Result<&SdkSuccess<DescribeTableOutput>, &SdkError<DescribeTableError>>,
    ) -> RetryKind {
        match self.inner.classify(response) {
            RetryKind::NotRetryable => (),
            other => return other,
        };
        match response {
            Ok(SdkSuccess { parsed, .. }) => {
                if parsed
                    .table
                    .as_ref()
                    .unwrap()
                    .table_status
                    .as_ref()
                    .unwrap()
                    == &TableStatus::Creating
                {
                    RetryKind::Explicit(Duration::from_secs(1))
                } else {
                    RetryKind::NotRetryable
                }
            }
            _ => RetryKind::NotRetryable,
        }
    }
}

/// Wait for the user to press Enter.
fn pause() {
    println!("Press Enter to continue.");
    stdin().read_exact(&mut [0]).unwrap();
}

/// Performs CRUD (create, read, update, delete) operations on a DynamoDB table and table item.
/// It creates a table, adds an item to the table, updates the item, deletes the item, and deletes the table.
/// The table name, primary key, and primary key value are all created as random strings.
///
/// # Arguments
///
/// * `[-i]` - Whether to pause between operations.
/// * `[-r REGION]` - The region in which the client is created.
///    If not supplied, uses the value of the **AWS_REGION** environment variable.
///    If the environment variable is not set, defaults to **us-west-2**.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt::init();
    let Opt {
        interactive,
        region,
        verbose,
    } = Opt::from_args();

    let region = region::ChainProvider::first_try(region.map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-west-2"));

    // Create 10-character random table name
    let table = random_string(10);

    // Create a 6-character random key name
    let key = random_string(6);

    // Create a 12-character random key value
    let value = random_string(12);

    // Specify first name, last name, age, and type
    let first_name = "DummyFirstName";
    let last_name = "DummyLastName";
    let age = "33";
    let utype = "standard_user";

    println!();

    if verbose {
        println!("DynamoDB client version: {}", PKG_VERSION);
        println!(
            "Region:                  {}",
            region.region().unwrap().as_ref()
        );
        println!("Table:                   {}", table);
        println!("Key:                     {}", key);
        println!("Value:                   {}", value);
        println!("First name:              {}", first_name);
        println!("Last name:               {}", last_name);
        println!("Age:                     {}", age);
        println!("User type:               {}", utype);

        println!();
    }

    let conf = Config::builder().region(region).build();
    let client = Client::from_conf(conf);

    /* Create table */
    println!("Creating the table.");
    match make_table(&client, &table, &key).await {
        Err(e) => {
            println!("Got an error creating the table:");
            println!("{}", e);
            process::exit(1);
        }
        Ok(_) => {
            println!("Created the table.");
        }
    }

    println!("Waiting for table to be ready.");

    let raw_client = aws_hyper::Client::https();

    raw_client
        .call(wait_for_ready_table(&table, client.conf()))
        .await
        .expect("table should become ready.");

    println!("Table is now ready to use.");

    if interactive {
        pause();
    }

    println!("Adding item to table.");

    let mut item = Item {
        table: table.clone(),
        key: key.clone(),
        value: value.clone(),
        first_name: first_name.to_string(),
        last_name: last_name.to_string(),
        age: age.to_string(),
        utype: utype.to_string(),
    };

    add_item(&client, item.clone()).await?;
    println!("Added item to table.");

    if interactive {
        pause();
    }

    item.age = "44".to_string();

    /* Update the item */
    println!("Modifying table item to change age to 44.");

    add_item(&client, item.clone()).await?;

    println!("Modified table item.");

    if interactive {
        pause();
    }

    /* Get item and compare it with the one we added */
    println!("Comparing table item to original value.");

    query_item(&client, item).await;

    if interactive {
        pause();
    }

    /* Delete item */
    println!("Deleting item.");
    let user_av = AttributeValue::S(value);
    client
        .delete_item()
        .table_name(&table)
        .key(key, user_av)
        .send()
        .await?;

    println!("Deleted item.");

    if interactive {
        pause();
    }

    /* Delete table */
    println!("Deleting table.");
    client.delete_table().table_name(&table).send().await?;
    println!("Deleted table.");
    println!();

    Ok(())
}

/// Construct a `DescribeTable` request with a policy to retry every second until the table
/// is ready
fn wait_for_ready_table(
    table_name: &str,
    conf: &Config,
) -> Operation<DescribeTable, WaitForReadyTable<AwsErrorRetryPolicy>> {
    let operation = DescribeTableInput::builder()
        .table_name(table_name)
        .build()
        .expect("valid input")
        .make_operation(&conf)
        .expect("valid operation");
    let waiting_policy = WaitForReadyTable {
        inner: operation.retry_policy().clone(),
    };
    operation.with_retry_policy(waiting_policy)
}
<|endoftext|>


<commit_before><commit_msg>Add test/example for a token struct<commit_after><|endoftext|>


<commit_before>//! The path element.

mod command;
mod data;
mod parameters;

pub use self::command::Command;
pub use self::data::Data;
pub use self::parameters::Parameters;

/// A number.
pub type Number = f32;

/// A type of positioning.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Position {
    /// Absolute.
    Absolute,
    /// Relative.
    Relative,
}
<commit_msg>Adjust the description of Position<commit_after>//! The path element.

mod command;
mod data;
mod parameters;

pub use self::command::Command;
pub use self::data::Data;
pub use self::parameters::Parameters;

/// A number.
pub type Number = f32;

/// A positioning method.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Position {
    /// Absolute.
    Absolute,
    /// Relative.
    Relative,
}
<|endoftext|>