How to pattern match on a value of type React.Ref.t(Js.Nullable.t('a)) - reason

I'm trying to access the DOM element as a JS object.
let navRef = React.useRef(Js.Nullable.null);
let width =
switch (Js.Nullable.toOption(navRef)) {
| None => 0.0
| Some(nav) => ReactDOMRe.domElementToObj(nav)##clientWidth
};
But I have a type eror on navRef inside Js.Nullable.toOption
Error: This expression has type React.Ref.t(Js.Nullable.t('a))
but an expression was expected of type
Js.Nullable.t('b) = Js.nullable('b)

React.Ref.t is an opaque type, hence you can't pattern match on it directly. But you can access the value of the ref using React.Ref.current and then pattern match on that:
let navRef = React.useRef(Js.Nullable.null);
let width =
switch (Js.Nullable.toOption(React.Ref.current(navRef))) {
| None => 0.0
| Some(nav) => ReactDOMRe.domElementToObj(nav)##clientWidth
};

Related

Convert Json array to list of strings

I am reading this tutorial https://www.stackbuilders.com/blog/nonsense-getting-started-with-reason-and-reason-react/. One of the problems I am facing is that api.noopschallenge.com is now dead. I replaced the API call to this https://random-word-api.herokuapp.com/word?number=20 This works but returns a Json Array. I have to convert the Json Array to list(string).
I modified the decodeWords function as
let decodeWord = (json: Js.Json.t) : list(string) =>
switch(Js.Json.decodeArray(json)) {
| None => []
| Some(array) => Belt.Array.map(Js.Json.decodeString, array)
};
But this gives me error
This has type:
Js.Json.t => option(Js.String.t) But somewhere wanted:
array('a)
How do I convert the Json Array to list(string)?
Two problems:
You've switched the arguments to Belt.Array.map around.´array` should come first.
Since decodeString returns an option(string) instead of just a string, you'll have to deal with the Nones somehow. Using Belt.Array.keepMap is a shorter way of just ignoring them.
let decodeWords = (json: Js.Json.t): list(string) =>
switch (Js.Json.decodeArray(json)) {
| None => []
| Some(array) =>
array->Belt.Array.keepMap(Js.Json.decodeString)->Belt.List.fromArray
};
But using the Js.Json API directly is rather cumbersome. You might want to consider using a third-party json decoding library such as bs-json (disclaimer: authored by me) instead. Then it would be as simple as:
let decodeWords = Json.Decode.(list(string))
Or, if you still want it to return an empty list instead of raising an exception on decode failure:
let decodeWords = Json.Decode.(withDefault([], list(string)))
I think I resolved it myself. but if you know of a better solution then please let me know
let decodeWords = (json: Js.Json.t) : list(string) =>
switch(Js.Json.decodeArray(json)) {
| None => []
| Some(array) => Belt.Array.reduce(array, [], (acc, value) => {
switch(Js.Json.decodeString(value)) {
| None => acc
| Some(v) => [v, ...acc]
}
})
};

Rust serde_json::value::RawValue gives errors "the trait bound ... `r2d2_postgres::postgres::types::FromSql<'_>` is not satisfied"

I am using r2d2_postgres to run raw SQL and return the result directly in Actix response.
I need to run raw sql with dynamic data, types and unknown at compile time columns/data types etc. To do this, I came across serde_json::value::RawValue:
It states: "A RawValue can be used to defer parsing parts of a payload until later, or to avoid parsing it at all in the case that part of the payload just needs to be transferred verbatim into a different output object."
https://docs.serde.rs/serde_json/value/struct.RawValue.html
I basically want to avoid parsing it at all and just send it to the Actix client.
Here's my code:
let mut conn = pool.get().expect("Couldn't get db connection from pool");
let result = web::block(move || conn.query("select jsonb_agg(t) from (select * from useraccountview) t",&[]))
.await;
match result {
Ok(result) => {
let foo : serde_json::value::RawValue = result[0].get(0);
HttpResponse::Ok().content_type("application/json").json(foo)
},
Err(e) => HttpResponse::NotAcceptable().body(e.to_string())
}
This gives me 2 errors:
error[E0277]: the trait bound `serde_json::value::RawValue: FromSql<'_>` is not satisfied
--> src/main.rs:188:63
|
188 | let foo : serde_json::value::RawValue = result[0].get(0);
| ^^^ the trait `FromSql<'_>` is not implemented for `serde_json::value::RawValue`
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> src/main.rs:188:17
|
188 | let foo : serde_json::value::RawValue = result[0].get(0);
| ^^^ doesn't have a size known at compile-time
I am very new to Rust so I am probably missing some concept on how to fix this.

Swift - Get case and value in enum with parameters

I have this enum
public enum Format {
case label(key: String)
case textField(key: String)
case image(key: String)
}
And I can use it like:
Format.label(key: "abc")
Format.textField(key: "0.0")
Format.image(key: "mystringfile")
When I try to get the value, I can do it with this:
let control = Format.label(key: "abc")
if case let Format.label(key) = control {
tmp = key
} else if case let Format.image(key) = control {
tmp = key
} else if case let Format.textField(key) = control {
tmp = key
}
With that I can get the value, but I'm not finding the case label, textfield or image.
How I can find the enum that belongs that variable?
If I try to use something like this:
control == Format.label
I get the error:
Binary operator '==' cannot be applied to operands of type
'Table.Format' and '(String) -> Format'
I may misunderstand your question but why not use a switch?
let control = Format.label(key: "abc") // or = Format.textField(key: "whatever") or = Format.image(key: "whatever")
let tmp: String
switch control {
case .label(let key):
// It's a label, do what you need
tmp = key
case .textField(let key):
// It's a textField, do what you need
tmp = key
case .image(let key):
// It's a image, do what you need
tmp = key
}
This lets you act on the type and get the value.

Why is a negative integer not a valid pattern in a macro?

Let us consider a simple enum implementation with a static method that check whether a value has an associated value (the efficiency of the implementation is not to be regarded here):
enum Letter {
Alpha = -1,
A = 0,
B = 1,
C = 2,
}
impl Letter {
pub fn in_enum(value: isize) -> bool
{
match value {
-1 => true,
0 => true,
1 => true,
2 => true,
_ => false,
}
}
}
Now, let us write a macro for building enums with an equivalent in_enum method. The macro below was written with some guidance from the Serde guide for enum deserialization as numbers, in which matching for enum variant values also occurs.
macro_rules! my_enum {
($name:ident { $($variant:ident = $value:expr, )* }) => {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum $name {
$($variant = $value,)*
}
impl $name {
pub fn in_enum(value: isize) -> bool
{
match value {
$( $value => true, )*
_ => false,
}
}
}
}
}
my_enum!(Letter {
Alpha = -1,
A = 0,
B = 1,
C = 2,
});
Playground.
With version 1.18.0, the compiler won't accept the variant with a negative integer.
error: expected pattern, found `-1`
--> src/main.rs:13:24
|
13 | $( $value => true, )*
| ^^^^^^
This seems to happen regardless of how I write this pattern down in the macro, or whether I use i32 or isize for the value method parameter. Changing the fragment specifier of $value to pat is also out of the question: the compiler will refuse to build the enum, even without negative variant values.
error: expected expression, found `-1`
--> src/main.rs:5:26
|
5 | $($variant = $value,)*
| ^^^^^^
What's surprising about this is that it works without using macros, as well as when I discard the Alpha variant.
Why does this happen?
This is a bug in the compiler and is already fixed in the nightly version as of today (Jul 5, 2017), and released in stable version 1.20.0.

Tracking down "missing parameter type for expanded function"

Im stuck with with code, whenever I try to run it I get the error:
Error:(37, 66) missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: com.bfg.domain.model.RunnerSnap
def syncPrices(pair: (RunnerSnap, RunnerChange)): RunnerSnap = {
However the error message is not enogh for me to know what I need to change to get this working.
def syncPrices(pair: (RunnerSnap, RunnerChange)): RunnerSnap = {
case (cache: RunnerSnap, delta: RunnerChange) =>
val newHc = if (delta.hc.isEmpty) cache.runnerId.handicap else delta.hc
val id = RunnerId(delta.id, newHc)
val prices = MarketRunnerPrices(
atl = syncPriceVolume(cache.prices.atl, delta.atl),
atb = syncPriceVolume(cache.prices.atb, delta.atb),
trd = syncPriceVolume(cache.prices.trd, delta.trd),
spb = syncPriceVolume(cache.prices.spb, delta.spb),
spl = syncPriceVolume(cache.prices.spl, delta.spl),
batb = syncLevelPriceVolume(cache.prices.batb, delta.batb),
batl = syncLevelPriceVolume(cache.prices.batl, delta.batl),
bdatb = syncLevelPriceVolume(cache.prices.bdatb, delta.bdatb),
bdatl = syncLevelPriceVolume(cache.prices.bdatl, delta.bdatl),
spn = if (delta.spn.isEmpty) cache.prices.spn else delta.spn,
spf = if (delta.hc.isEmpty) cache.prices.spf else delta.spf,
ltp = if (delta.hc.isEmpty) cache.prices.ltp else delta.ltp,
tv = if (delta.hc.isEmpty) cache.prices.tv else delta.tv
)
RunnerSnap(id, prices)
}
My question is: Why am I getting this error and what do I need to
change in my code to get it working as expected?
You are missing pair match:
def syncPrices(pair: (RunnerSnap, RunnerChange)): RunnerSnap = pair match {
case (cache: RunnerSnap, delta: RunnerChange) =>
...
}