Using Rust libraries reqwest and select in conjunction - select

I am trying to follow the example here:
https://rust-lang-nursery.github.io/rust-cookbook/web/scraping.html, which utilizes both Reqwest and Select in order to get an html response then parse the data.
I am using Reqwest version 0.10.4 and Select version 0.4.3 which are the versions it shows in the example. However, I am getting an error:
error[E0277]: the trait bound `reqwest::Response: std::io::Read` is not satisfied
--> src/main.rs:19:25
|
19 | Document::from_read(res)?
| ^^^ the trait `std::io::Read` is not implemented for `reqwest::Response`
|
::: /root/.cargo/registry/src/github.com-1ecc6299db9ec823/select-0.4.3/src/document.rs:31:25
|
31 | pub fn from_read<R: io::Read>(mut readable: R) -> io::Result<Document> {
| -------- required by this bound in `select::document::Document::from_read`
It seems like the from_read method takes in a Read type but the reqwest::get method returns a different type. Is there some sort of conversion that must be done first before the response is passed to the from_read method?
This is the example:
#[macro_use]
extern crate error_chain;
extern crate reqwest;
extern crate select;
use select::document::Document;
use select::predicate::Name;
error_chain! {
foreign_links {
ReqError(reqwest::Error);
IoError(std::io::Error);
}
}
fn main() -> Result<()> {
let res = reqwest::get("https://www.rust-lang.org/en-US/").await?;
Document::from_read(res)?
.find(Name("a"))
.filter_map(|n| n.attr("href"))
.for_each(|x| println!("{}", x));
Ok(())
}

reqwest::get returns a Result<Response>, then with the ? you are unwrapping the Result, meaning you now have a Response object as documented here. And because a web call can successfully occur but still fail (see HTTP non 200 codes) you should check the response code, but since this is to learn we'll ignore it. What you want is a struct that implements the std::io::Read trait, reading up on that shows that String implements that trait. Going back to reqwest::Response shows that we can get the string returned using the method text(). So your code now becomes
let res = reqwest::get("https://www.rust-lang.org/en-US/")
.await?
.text()
.await?;
Update from the comments: Now the problem is that Document::from_read only accepts std::io::Read as parameters, and std::string::String does not implement that trait, and instead of using a crate like stringreader we can simply use Document::from as document implements the From<&'a str> trait.
And, as with almost everything, there are multiple ways of solving this. You could either
Create the Document from the string directly with Document::from(res), or
Convert the string to a byte slice, which implements Read, and create the document from that with Document::from_read(res.as_bytes())

Related

Using socket2 with hyper

I am writing a http server that works with it's host machine via a unix domain sockets. The server is written using hyper and I am connecting to UDS via socket2.
This is my code:
let socket = Socket::new(Domain::UNIX, Type::STREAM, None)?;
let socket_address = SockAddr::unix("unix://tmp/test.sock")?;
socket.bind(&socket_address)?;
socket.listen(128)?;
let server = hyper::server::Server::builder(socket.into()).serve(service);
What is the right way to do this? I am getting an error saying cannot infer type for type parameter I
error[E0698]: type inside `async fn` body must be known in this context
--> src/server.rs:65:64
|
65 | let server = hyper::server::Server::builder(socket.into()).serve(service);
| ^^^^^ cannot infer type for type parameter `I`
|
note: the type is part of the `async fn` body because of this `await`
--> src/server.rs:66:13
|
66 | let _ = server.await?;
| ^^^^^^^^^^^^
I is the generic parameter to hyper::server::Server. While I am aware what is causing the issue: compiler not able to determine what does socket.into() get cast to, I don't know to solve it.
Please correct if my understanding is wrong. Can I get some help in this?
You need to convert the socket into a type such as tokio::net::UnixListener. Once you have done this, you need an implementation of the Accept trait. You can implement that trait in the following manner:
use hyper::server::accept::Accept;
use tokio::net::UnixListener;
use std::pin::Pin;
use std::task::{Context, Poll};
pub struct UDSAccept {
inner: UnixListener,
}
impl Accept for UDSAccept {
type Conn = tokio::net::UnixStream;
type Error = std::io::Error;
fn poll_accept(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
match self.inner.poll_accept(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(Ok((socket, _addr))) => Poll::Ready(Some(Ok(socket))),
Poll::Ready(Err(err)) => Poll::Ready(Some(Err(err))),
}
}
}
The above type will be usable as the argument to Server::builder.
If the constructor that comes with the Tokio type does not provide all the options you need and you still wish to use socket2 to construct it, you can do so by first converting it to the std UnixListener and then calling Tokio's from_std method. Be aware that you must set the socket in non-blocking mode yourself when doing this!

How to enumerate over columns with tokio-postgres when the field types are unknown at compile-time?

I would like a generic function that converts the result of a SQL query to JSON. I would like to build a JSON string manually (or use an external library). For that to happen, I need to be able to enumerate the columns in a row dynamically.
let rows = client
.query("select * from ExampleTable;")
.await?;
// This is how you read a string if you know the first column is a string type.
let thisValue: &str = rows[0].get(0);
Dynamic types are possible with Rust, but not with the tokio-postgres library API.
The row.get function of tokio-postgres is designed to require generic inference according to the source code
Without the right API, how can I enumerate rows and columns?
You need to enumerate the rows and columns, doing so you can get the column reference while enumerating, and from that get the postgresql-type. With the type information it's possible to have conditional logic to choose different sub-functions to both: i) get the strongly typed variable; and, ii) convert to a JSON value.
for (rowIndex, row) in rows.iter().enumerate() {
for (colIndex, column) in row.columns().iter().enumerate() {
let colType: string = col.type_().to_string();
if colType == "int4" { //i32
let value: i32 = row.get(colIndex);
return value.to_string();
}
else if colType == "text" {
let value: &str = row.get(colIndex);
return value; //TODO: escape characters
}
//TODO: more type support
else {
//TODO: raise error
}
}
}
Bonus tips for tokio-postgres code maintainers
Ideally, tokio-postgres would include a direct API that returns a dyn any type. The internals of row.rs already use the database column type information to confirm that the supplied generic type is valid. Ideally a new API uses would use the internal column information quite directly with improved FromSQL API, but a simpler middle-ground exists:-
It would be possible for an extra function layer in row.rs that uses the same column type conditional logic used in this answer to then leverage the existing get function. If a user such as myself needs to handle this kind of conditional logic, I also need to maintain this code when new types are handled by tokio-postgresql, therefore, this kind of logic should be included inside the library where such functionality can be better maintained.

Type wrapping of non-atomic types in golang

I'm new to golang and am trying to understand a code example of type wrapping for the "non-atomic" type time.Time.
The type extension in question is from the Go client for GDAX on github, go-coinbase-exchange project.
The expected behavior would be for Time variables from the project (coinbase.Time), which are of type Time time.Time (as defined in the project's time.go file) to behave something like the following example for extending the "atomic" type int (from blog.riff.org in that they might follow a kind of "inheritance" from the base type for functions like Time.format (from golang's standard implementation of time:
package main
import "fmt"
type Int int
func (i Int) Add(j Int) Int {
return i + j
}
func main() {
i := Int(5)
j := Int(6)
fmt.Println(i.Add(j))
fmt.Println(i.Add(j) + 12)
}
But if I modify the code example from the project's List Account Ledger example found in Readme.md to include a print function which might otherwise give me a human-readable view of the CreatedAt struct variables (as follows), I get a compiler error saying that "type coinbase.Time has no field or method Format":
for _, e := range ledger {
print("Entry Creation: ")
fmt.Printf(e.CreatedAt.Format("2006-01-02 15:04:05.999999+00"))
}
The expected behavior inside the for loop would be for it to print the ledger entries in a human-readable format. I can get the contents of the structs, but I'm not really sure how to then use the resulting wall, ext and loc members.
For example, inserting fmt.Printf("%#v", e.CreatedAt) into the for loop gives me a representation of the time that looks something like this:
coinbase.Time{wall:0x3015a123, ext:63612345678, loc:(*time.Location)(nil)}
{806986000 63638738354 <nil>}
I can also see that wall is of type uint64, that ext is of type int64 and that loc is just GMT/UTC=0 by formatting the variable as a string because fmt.Printf("%s", e.CreatedAt) gives me output which is similar to the following:
{%!s(uint64=712345678) %!s(int64=63612345678) %!s(*time.Location=<nil>)}
It seems like I'm missing something. I've requested further information through issues tab on github, but maybe this is a nube question. So I'm not sure how quick the response time would be, and I'm interested in the more general case for extending non-atomic types in go.
Named types do not inherit any methods from the underlying type (indeed there is no inheritance at all in Go); you must cast to the underlying type to call any methods from that type:
(time.Time(e.CreatedAt)).Format("2006-01-02 15:04:05.999999+00")

Rust method that returns token name as a string

The stringify macro returns the string of a token passed to it:
struct A;
fn main() {
let my_identifier = A {};
assert!(stringify!(my_identifier) == "my_identifier");
}
[playground]
Is there a way to for a method to return the string of the token on which it is called?
Something like:
struct A;
impl A {
fn token_to_string(&self) -> &str{
/* ... */
}
}
fn main() {
let my_identifier = A {};
assert!(my_identifier.token_to_string() == "my_identifier");
}
[playground]
Googling for this has not been fruitful. I'm not sure if it's possible, but I thought it reasonable to ask here before diving into the implementation of stringify which would be my next step in investigating this.
No, this is not possible. These two constructs execute at different times in different contexts.
Macros execute during the process of compilation, and thus have access to all of the information about the original source files. This means they are able to process individual source tokens and perform operations based on them.
Methods execute when your program itself runs, and only have access to their arguments, and global variables. They have no data about the original sourcecode of the application, because that information is not stored in the compiled binary.

Java 8 Optional.ifPresent is my code wrong or is it eclipse?

I am new to Java 8 and trying out Null type annotations and Optional.
For my example below, I have used String rather than my class and am calling toUpperCase just to call something, in my case I actually call a function passing in a parameter (so don't think I can use :: operator and/or maps).
In Eclipse I have the Java - Compiler - Errors/Warnings - Null Analysis Errors turned on.
My test code below:
public void test1(#Nullable String s) {
// the 2nd s2 has a Potential null pointer access error.
// I was hoping ifPresent would imply NonNull
Optional.ofNullable(s).ifPresent(s2 -> s2.toUpperCase());
}
#Nullable
public String getSomeString() {
return null;
}
public void test2() {
String s = getSomeString();
// This is fine, unlike the first example, I would have assumed that
// it would know s was still nullable and behave the same way.
Optional.ofNullable(s).ifPresent(s2 -> s2.toUpperCase());
}
It would seem that using Eclipse type null annotations and Optional.ifPresent doesn't go well together.
Am I wasting my time trying to get something like this to work? Should I just revert back to assigning the getter to a temp var then checking if null, and if not call my function?
JDT's null analysis cannot know about the semantics of each and every method in JRE and other libraries. Therefore, no conclusions are drawn from seeing a call to ifPresent. This can be remedied by adding external annotations to Optional so that the analysis will see method ofNullable as
<T> Optional<#NonNull T> ofNullable(#Nullable T value)
External annotations are supported starting with Eclipse Mars, released June, 24, 2015. See Help: Using external null annotations.
The difference between the two variants in the question is due to how null analysis is integrated with Java 8 type inference: In variant (1) s has type #Nullable String. When this type is used during type inference, it is concluded that the argument to ifPresent is nullable, too. In variant (2) s has type String (although flow analysis can see that is may be null after the initialization from getSomeString). The unannotated type String is not strong enough to aid type inference to the same conclusion as variant (1) (although this could possibly be improved in a future version of JDT).
First of: #Nullable seams not to be part of the public Java 8 SDK. Have a look at the package you imported: com.sun.istack.internal.Nullable.
Second: I have run both of your methods: test1(null) and test2() and nothing out of the ordinary happened. Everything was fine (as expected). So what did you observe?
run test1(null) => no execution of lambda expression.
run test2() => no execution of lambda expression.
I changed your code for testing in the following way:
public void test1(#Nullable String s) {
Optional.ofNullable(s).ifPresent(s2 -> System.out.println("executed"));
}
public void test2() {
String s = getSomeString();
Optional.ofNullable(s).ifPresent(s2 -> System.out.println("executed"));
}