I'm trying to select on a subset of enum variants, but getting the trait PgHasArrayType is not implemented. Any suggestions?
use sqlx::Row;
#[derive(Debug, sqlx::Type)]
#[sqlx(type_name = "color")]
#[sqlx(rename_all = "lowercase")]
enum Color {
Red,
Green,
Blue,
}
#[tokio::main]
async fn main() -> sqlx::Result<()> {
dotenv::dotenv().ok();
let db = sqlx::PgPool::connect(&std::env::var("DATABASE_URL").unwrap()).await?;
let mut tnx = db.begin().await?;
sqlx::query("CREATE TYPE color AS ENUM ('red', 'green', 'blue')")
.execute(&mut tnx)
.await?;
sqlx::query("CREATE TABLE colors (color color)")
.execute(&mut tnx)
.await?;
sqlx::query("INSERT INTO colors VALUES ('red'), ('green')")
.execute(&mut tnx)
.await?;
/// Querying by a single enum works
assert_eq!(
sqlx::query("SELECT color FROM colors WHERE color = $1")
.bind(Color::Red)
.fetch_one(&mut tnx)
.await?
.get::<Color, &str>("color"),
Color::Red
);
/// Error: the trait `PgHasArrayType` is not implemented for `Color`
sqlx::query("SELECT color FROM colors WHERE color = ANY($1)")
.bind(&[Color::Blue, Color::Red])
.fetch_one(&mut tnx)
.await?
.get::<Color, &str>("color");
tnx.rollback().await?;
Ok(())
}
Related
I have a type T that implements display (so it has a .to_string() method)
let my_vec = vec![T(), T(), T()];
println!("{}", my_vec.join(", "));
sadly errors with "trait bounds not satisfied" because the separator, ", ", is not of the same type as the vector's items (I'm pretty sure).
I guess my workaround is then
println!("{}", my_vec.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", "));
But isn't there anything shorter and clearer that I can write out instead of this?
I've just written this function to help me out:
fn join<T, I>(vec: &[T], sep: I) -> String
where
T: std::fmt::Display,
I: std::fmt::Display,
{
vec.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(&sep.to_string())
}
But I'd rather not have to. There must be alternative solutions that: are already built-in, don't require manual implementation, at least don't require the creation of a top-level function that's then only called twice.
AFAIK, your work around is good and sound without non-std libs.
Several cargos provide some helper functions for this issue, for example:
Playground
itertools and joinery
use itertools::Itertools;
use joinery::Joinable;
struct Color {
red: u8,
green: u8,
blue: u8,
}
impl std::fmt::Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"RGB ({}, {}, {}) 0x{:02X}{:02X}{:02X}",
self.red, self.green, self.blue, self.red, self.green, self.blue
)
}
}
fn main() {
let colors = vec![
Color {
red: 128,
green: 255,
blue: 90,
},
Color {
red: 0,
green: 3,
blue: 254,
},
];
println!(
"{}",
colors
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(", ")
);
println!("{}", colors.iter().join(", "));
println!("{}", colors.join_with(", "));
}
I have an enum type Shape that contains two types Rect and Circle. now there is a function that can find &Rect or &Circle objects, how can I get them to return as &Shape?
#[derive(Debug)]
struct Rect {}
#[derive(Debug)]
struct Circle {}
#[derive(Debug)]
enum Shape {
R(Rect),
C(Circle),
}
struct Container {
rects: Vec<(usize, Rect)>,
circls: Vec<(usize, Circle)>,
}
impl Container {
fn find_shape(&self, id: usize) -> Option<&Shape> {
let optr = self.rects.iter().find(|x| x.0 == id);
if let Some((_, r)) = optr {
return Some(&Shape::R(r)); // expected struct `Rect`, found `&Rect`
}
let optc = self.circls.iter().find(|x| x.0 == id);
if let Some((_, c)) = optc {
return Some(c); // expected enum `Option<&Shape>` found reference `&Circle`
}
return None;
}
}
fn main() {
let cont = Container {
rects: vec![(0, Rect {}), (2, Rect {})],
circls: vec![(1, Circle {}), (3, Circle {})],
};
let s = cont.find_shape(1).unwrap();
println!("shape is {:?}", s);
}
now there is a function that can find &Rect or &Circle objects, how can I get them to return as &Shape?
It can't, in the same way you can't get e.g. an &Option<String> from an &String.
Shape is, in essence,
struct Shape {
discr: u8,
content: union { _1: Rect, _2: Circle }
}
The solution is to either modify Shape to store references, or to have a secondary type which does that (e.g. ShapeRef).
The latter is quite common.
I am trying to render text in a separate function using piston2d / piston_window. I am able to draw text just fine, but I can't figure out how to pass the appropriate parameters into a separate function.
I have studied What is GlyphCache type in a function to render text in Piston2d and adjusted my code accordingly, but I can't make sense of the error I am getting.
use piston_window::*;
fn main() {
let font = include_bytes!("IBMPlexSans-Regular.ttf");
let opengl = OpenGL::V3_2;
let settings = WindowSettings::new("test", [500, 500])
.graphics_api(opengl)
.fullscreen(false)
.vsync(true)
.exit_on_esc(true);
let mut window: PistonWindow = settings.build().unwrap();
let mut glyphs = Glyphs::from_bytes(
font,
window.create_texture_context(),
TextureSettings::new(),
)
.unwrap();
while let Some(e) = window.next() {
window.draw_2d(&e, |c, gfx, device| {
clear([0.2; 4], gfx);
text::Text::new_color([1.0, 1.0, 1.0, 0.7], 30)
.draw(
"Hi!",
&mut glyphs,
&c.draw_state,
c.transform
.trans(100., 100.),
gfx,
)
.unwrap();
glyphs.factory.encoder.flush(device);
});
}
}
fn render_text(
x: f64,
y: f64,
text: &str,
size: u32,
c: Context,
g: &mut G2d,
glyphs: &mut glyph_cache::rusttype::GlyphCache<GfxFactory, G2dTexture>,
) {
text::Text::new(size)
.draw(text, glyphs, &c.draw_state, c.transform.trans(x, y), g)
.unwrap();
}
I am receiving the following error:
error[E0277]: the trait bound `Texture<gfx_device_gl::Resources>: UpdateTexture<gfx_device_gl::factory::Factory>` is not satisfied
--> src/main.rs:54:10
|
54 | .draw(text, glyphs, &c.draw_state, c.transform.trans(x, y), g)
| ^^^^ the trait `UpdateTexture<gfx_device_gl::factory::Factory>` is not implemented for `Texture<gfx_device_gl::Resources>`
|
= help: the following implementations were found:
<Texture<R> as UpdateTexture<TextureContext<F, R, C>>>
= note: required because of the requirements on the impl of `CharacterCache` for `GlyphCache<'_, gfx_device_gl::factory::Factory, Texture<gfx_device_gl::Resources>>`
I am aware this is probably very piston-specific, but I would be very happy about any pointers.
Just had the same problem. It's almost a year after but documentation for piston_window isn't the best so maybe others will need it.
This worked for me
use piston_window::types::Color;
use piston_window::{text, Context, G2d, Glyphs, Transformed};
pub const text_color: Color = [1.0, 1.0, 1.0, 1.0];
pub fn draw_text(
ctx: &Context,
graphics: &mut G2d,
glyphs: &mut Glyphs,
color: Color,
pos: Position,
text: &str,
) {
text::Text::new_color(color, 20)
.draw(
text,
glyphs,
&ctx.draw_state,
ctx.transform.trans(pos.x as f64, pos.y as f64),
graphics,
)
.unwrap();
}
pub struct Pos {
pub x: f64,
pub y: f64,
}
pub fn main() {
let assets = find_folder::Search::ParentsThenKids(3, 3)
.for_folder("assets")
.unwrap();
let ref font = assets.join("retro-gaming.ttf");
let mut glyphs = window.load_font(font).unwrap();
let size = [500., 500.];
let mut window: PistonWindow = WindowSettings::new("Test", size)
.resizable(false)
.exit_on_esc(true)
.build()
.unwrap();
while let Some(event) = window.next() {
window.draw_2d(&event, |ctx, g, _| {
draw_text(&ctx, g, &mut glyphs, text_color, Pos { x: 0, y: 10 }, "20")
}
}
}
Note that I'm using different "Glyphs" than you are. There's additionally one more dependency in "Cargo.toml" namely find_folder = "0.3.0".
I'm not entirely sure whether the snippet above compiles and works. It is a quick refactor from this commit https://github.com/laszukdawid/rsnake/commit/e6e23563ebdd9c7b972ee17b5d0299e2202358cf.
I'm using the noise crate and having trouble understanding how to convert their Color type to an RGB value.
noise = "0.7.0"
pub type Color = [u8; 4];
I'm trying to use the get_value() function, seen here in the docs as:
pub fn get_value(&self, x: usize, y: usize) -> Color {
let (width, height) = self.size;
if x < width && y < height {
self.map[x + y * width]
} else {
self.border_color
}
}
get_value() is implemented for PlaneMapBuilder. So I would expect PlaneMapBuilder::get_value(x,y) to return something of the format [r,g,b,a], but this does not happen:
extern crate noise;
use noise::{utils::*, Billow};
fn main() {
let mut my_noise = PlaneMapBuilder::new(&Billow::new()).build();
let my_val = my_noise.get_value(1,1);
println!("{}", my_val.to_string());
///returns something like -0.610765515150546, not a [u8;4] as I would expect
}
In the docs I see this definition of add_gradient_point() which takes a Color as a parameter:
pub fn add_gradient_point(mut self, pos: f64, color: Color) -> Self {
// check to see if the vector already contains the input point.
if !self
.gradient_points
.iter()
.any(|&x| (x.pos - pos).abs() < std::f64::EPSILON)
{
// it doesn't, so find the correct position to insert the new
// control point.
let insertion_point = self.find_insertion_point(pos);
// add the new control point at the correct position.
self.gradient_points
.insert(insertion_point, GradientPoint { pos, color });
}
self
}
Here they use the [u8; 4] structure I would expect for the Color type:
let jade_gradient = ColorGradient::new()
.clear_gradient()
.add_gradient_point(-1.000, [24, 146, 102, 255])
.add_gradient_point(0.000, [78, 154, 115, 255])
What could explain this behavior?
get_value() is implemented for PlaneMapBuilder
You are correct that PlaneMapBuilder "implements" get_value(). However, it is not get_value() from NoiseImage. It is actually NoiseMap, where its get_value() returns a f64 and not Color.
Depending on what kind of "colors" you'd want, then you could instead use ImageRenderer and call its render() method with &my_noise, which returns a NoiseImage.
// noise = "0.7.0"
use noise::{utils::*, Billow};
fn main() {
let my_noise = PlaneMapBuilder::new(&Billow::new()).build();
let image = ImageRenderer::new().render(&my_noise);
let my_val = image.get_value(1, 1);
println!("{:?}", my_val);
// Prints: `[18, 18, 18, 255]`
}
Here they use the [u8; 4] structure I would expect for the Color type
Just to be clear, those are the same thing in this case. In short the type keyword allows you to define new "type aliases" for an existing types. Essentially, you'd be able to give a complex type a shorthand name. However, they are still the same type.
I'm trying to write a raytracer in Rust. I'm having difficulty getting the for loops to run in parallel. I'm not sure where the problem is, but I can't seem to get anything on the screen. Is this the correct approach or am I completely heading in the wrong direction?
I've tried running the for loops without multi-threading and it does correctly produce output. I've also added loggers to the consumer loop and I'm getting the correct values as well. It just doesn't seem to update the window.
#[derive(Clone, Copy)]
pub struct Pixel {
pub x: usize,
pub y: usize,
pub color: Vec3,
}
let mut buffer : Vec<u32> = vec![0; WIDTH * HEIGHT];
let (tx, rx) = mpsc::channel()
for x in 0..HEIGHT {
let tx_t = tx.clone();
thread::spawn(move || {
for y in 0..WIDTH {
let mut color = cast_ray(x, y); // returns vec3
let pixel = Pixel { x: x, y: y, color: color };
tx_t.send(pixel).unwrap();
}
});
}
for received in rx {
buffer[received.x * WIDTH + received.y] = received.color.x << 16 | received.color.y << 8 | received.color.z;
}
while window.is_open() && !window.is_key_down(Key::Escape) {
window.update_with_buffer(&buffer).unwrap();
}
I'm expecting a few spheres or color to appear on the screen, but it's just black.