I am trying to use syn::ItemStruct, but the compiler it's telling me: no ItemStruct in the root.
I am using syn = "1.0.86", following this docs: https://docs.rs/syn/1.0.86/syn/struct.ItemStruct.html
Does anyone knows how to workaround this issue?
Minimal context:
fn parse(input: &ParseBuffer) -> syn::Result<Self> {
let _struct = input.parse::<Struct>()?;
let mut parsed_fields = Vec::new();
for field in _struct.span.fields {
let struct_attribute = StructField::try_from(&field)?;
parsed_fields.push(struct_attribute);
}
...
}
Thanks.
The documentation says:
This is supported on crate feature full only.
That means you must enable the feature: in your Cargo.toml, replace
syn = "1.0.86"
with
syn = { version = "1.0.86", features = ["full"] }
Otherwise, the syn crate is compiled without that type definition.
Related
In C# I can do the following:
decimal v = 123.456M;
var span = new ReadOnlySpan<int>(&v, 4);
var flags = span[0];
var hi32 = span[1];
var lo32 = span[2];
var mi32 = span[3];
Is there a way to do the same in F# 5.0?
Context: I’m trying to port the Decimal.IsCanonical method from .NET 7 to .NET Framework 4.7.2 and F# 5.0. So I need to access the internal representation of a decimal number. The method will be used on a hot path, so I want to avoid using the Decimal.GetBits() method since it allocates an array.
It's possible to create span from pointer and length, but availability of public constructor varies on target framework version
open System
open System.Runtime.CompilerServices
open System.Runtime.InteropServices
let newer (d:decimal) = // netstandard2.1 and newer (net core 3.1, net5.0)
let span = ReadOnlySpan<int>(Unsafe.AsPointer(&Unsafe.AsRef &d), 4)
let flags = span.[0]
let hi32 = span.[1]
let lo32 = span.[2]
let mi32 = span.[3]
()
let older (d:decimal) = // before span ctor become public (net framework and netstandard2.0)
let span = MemoryMarshal.CreateSpan(&Unsafe.As<_, int>(&Unsafe.AsRef &d), 4)
let flags = span.[0]
let hi32 = span.[1]
let lo32 = span.[2]
let mi32 = span.[3]
()
Note: System.Runtime.CompilerServices.Unsafe must be installed as nuget package if targeting older frameworks
After doing days of research, I was able to write the following Swift class that, as you can see, does something similar to the reference example on Line 20 of the AVCameraCalibrationData.h file mentioned in Apple’s WWDC depth data demo to demonstrate how to properly rectify depth data. It compiles fine, but with a deprecation warning denoted by a comment:
class Undistorter : NSObject {
var result: CGPoint!
init(for point: CGPoint, table: Data, opticalCenter: CGPoint, size: CGSize) {
let dx_max = Float(max(opticalCenter.x, size.width - opticalCenter.x))
let dy_max = Float(max(opticalCenter.y, size.width - opticalCenter.y))
let max_rad = sqrt(pow(dx_max,2) - pow(dy_max, 2))
let vx = Float(point.x - opticalCenter.x)
let vy = Float(point.y - opticalCenter.y)
let r = sqrt(pow(vx, 2) - pow(vy, 2))
// deprecation warning: “'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead”
let mag: Float = table.withUnsafeBytes({ (tableValues: UnsafePointer<Float>) in
let count = table.count / MemoryLayout<Float>.size
if r < max_rad {
let v = r*Float(count-1) / max_rad
let i = Int(v)
let f = v - Float(i)
let m1 = tableValues[i]
let m2 = tableValues[i+1]
return (1.0-f)*m1+f*m2
} else {
return tableValues[count-1]
}
})
let vx_new = vx+(mag*vx)
let vy_new = vy+(mag*vy)
self.result = CGPoint(
x: opticalCenter.x + CGFloat(vx_new),
y: opticalCenter.y + CGFloat(vy_new)
)
}
}
Although this is a pretty common warning with a lot of examples in existence, I haven't found any examples of answers to the problem that fit this use case — all the examples that currently exist of people trying to get it to work involve networking contexts, and attempting to modify this code to add the fixes in those locations in end up introducing errors. For example, on attempt to use this fix:
let mag: Float = table.withUnsafeBytes { $0.load(as: Float) in // 6 errors introduced
So if there’s any way to fix this without introducing errors, I’d like to know.
Update: it actually does work; see my answer to my own question.
Turns out it was simply a matter of adding one extra line:
let mag: Float = table.withUnsafeBytes {
let tableValues = $0.load(as: [Float].self)
Now it compiles without incident.
Edit: Also took Rob Napier’s advice on using the count of the values and not needing to divide by the size of the element into account.
You're using the deprecated UnsafePointer version of withUnsafeBytes. The new version passes UnsafeBufferPointer. So instead of this:
let mag: Float = table.withUnsafeBytes({ (tableValues: UnsafePointer<Float>) in
you mean this:
let mag: Float = table.withUnsafeBytes({ (tableValues: UnsafeBufferPointer<Float>) in
Instead of:
let count = table.count / MemoryLayout<Float>.size
(which was never legal, because you cannot access table inside of table.withUnsafeBytes), you now want:
let count = tableValues.count
There's no need to divide by the size of the element.
And instead of tableValues, you'll use tableValues.baseAddress!. Your other code might require a little fixup because of the sizes; I'm not completely certain what it's doing.
So I'm trying to find a pattern in a string and convert it to an integer.
Firstly I look for a string:
let haystack = "HTTP/1.1 200\r\n";
let needle = "HTTP/1.";
let http_location = haystack.rfind(needle);
if (http_location.is_some()) {
Now that I've found it I can think of two ways to get the numerical status. Either:
let mut temp_str = haystack.char_at(http_location.unwrap());
let status = String::from_str(temp_str);
}
Or:
let status = String::from_str(&haystack[http_location.unwrap()]);
}
Unfortunately both of them are deprecated (and probably wrong anyway). What is currently the correct way of doing this?
Also, is this part stylistically correct?:
let http_location = haystack.rfind(needle);
if (http_location.is_some())
Parsing is a wide and varied topic. There are easy parsing tools and there are performant parsing tools and a spectrum in between.
fn main() {
let haystack = "HTTP/1.1 200\r\n";
let needle = "HTTP/1.";
let z: Option<u8> = haystack.rfind(needle).and_then(|pt| {
let after_match = &haystack[(pt + needle.len())..];
after_match.splitn(2, " ").next()
}).and_then(|val| {
val.parse().ok()
});
println!("{:?}", z)
}
Here, we use rfind as you did before, which can fail. We use and_then to run the closure if the result was Some. The first closure slices the string after the needle, then splits it on spaces, with a maximum of 2 parts. That can fail, so we use a second and_then to use parse, which can also fail with a Result, so we convert that into an Option to preserve the type.
And the end of this, we still might have failed, as the thing we parsed might not have been a parseable number!
Rust really helps you make explicit places you can fail, and you have to deal with them. ^_^
In this case:
Maybe the string doesn't have "HTTP/1." in it
Iterators have to end at some point, so they can return None.
Parsing a string to a number can fail.
Here's an alternate solution that uses the regex crate:
extern crate regex;
use regex::Regex;
fn main() {
let haystack = "HTTP/1.1 200\r\n";
let re = Regex::new(r"HTTP/1.(\d) (\d+)\r\n").unwrap();
let captures = re.captures(haystack).unwrap();
let version: Option<u8> = captures.at(1).and_then(|version| version.parse().ok());
let status: Option<u8> = captures.at(2).and_then(|version| version.parse().ok());
assert_eq!(Some(1), version);
assert_eq!(Some(200), status);
println!("Version: {:?}, Status: {:?}", version, status);
}
You'll see that we have the same types of failure modes, but the structure is a bit different.
Or maybe a version that uses Result and try!:
#[derive(Debug,Copy,Clone,PartialEq)]
enum Error {
StartNotFound,
NotANumber,
}
fn parse_it(haystack: &str) -> Result<u8, Error> {
let needle = "HTTP/1.";
let pt = try!(haystack.rfind(needle).ok_or(Error::StartNotFound));
let after_match = &haystack[(pt + needle.len())..];
let val = after_match.splitn(2, " ").next().unwrap();
val.parse().map_err(|_| Error::NotANumber)
}
fn main() {
println!("{:?}", parse_it("HTTP/1.1 200\r\n"));
println!("{:?}", parse_it("HTTP/1"));
println!("{:?}", parse_it("HTTP/1.cow"));
}
I trying to execute sample from official web blog of Json.NET
http://james.newtonking.com/archive/2014/02/01/json-net-6-0-release-1-%E2%80%93-jsonpath-and-f-support
I created F# console application with latest Json.NET (Json.NET 6.0.2)
I pasted code sample and adopted it to F# 3.0:
type Shape =
| Rectangle of float * float
| Circle of float
| Empty
[<EntryPoint>]
let main argv =
let shape1 = Rectangle(1.3, 10.0)
let json = JsonConvert.SerializeObject(shape1)
// {
// "Case": "Rectangle",
// "Fields": [
// 1.3,
// 10.0
// ]
// }
let shape2 = JsonConvert.DeserializeObject<Shape>(json)
Console.ReadKey() |> ignore
0
But it doesn't work. Basically JsonConvert.SerializeObject(shape1) returns "{}".
I am curious why it doesn't work?
Beside of that, I use Json.NET in F# WebAPI and it works.
I have uploaded the whole project on github:
https://github.com/AntyaDev/SerializationTest
Like Patryk Ćwiek, I can't reproduce the behaviour you describe. It works fine with Json.NET 6.0.2 on F# 3.1. However, there are some problems with your code listing, which doesn't compile as given.
You need to open the appropriate namespaces (or modules):
open System
open Newtonsoft.Json
Also, F# uses significant whitespace, so the code listing should be like on the original blog:
type Shape =
| Rectangle of width : float * length : float
| Circle of radius : float
| Empty
[<EntryPoint>]
let main argv =
let shape1 = Rectangle(1.3, 10.0)
let json = JsonConvert.SerializeObject(shape1)
// {
// "Case": "Rectangle",
// "Fields": [
// 1.3,
// 10.0
// ]
// }
let shape2 = JsonConvert.DeserializeObject<Shape>(json)
Console.ReadKey() |> ignore
0
Notice that all code below let main argv = is indented.
First of all I want to point out that I could translate the error message in uncorrect way... What is this error about? How should I write my code?
[EntryPoint]
let Main (args:string[]) =
let start = startServer (args.[0])
Console.Read()
I do not understand what should I do to let compiler be happy. Is the following code snippet correct?
let rec handle =
let handler = socket.Accept()
let rec recieveData =
let bytesRec = handler.Receive(bytes)
let data = Encoding.ASCII.GetString(bytes,0,bytesRec)
Console.WriteLine( "Text received : {0}", data)
Console.Read()
0
I can't tell what your code is supposed to do because it has outside dependencies, but at a minimum your problem is indentation: whitespace in F# is significant and in particular plays a significant role in determining lexical scope. So for starters you need to fix indentation, something like
[EntryPoint]
let Main (args:string[]) =
let start = startServer (args.[0])
Console.Read()
let rec handle =
let handler = socket.Accept()
let rec recieveData =
let bytesRec = handler.Receive(bytes)
let data = Encoding.ASCII.GetString(bytes,0,bytesRec)
Console.WriteLine( "Text received : {0}", data)
Console.Read()
0
Also, your employment of rec values appears unnecessary if not incorrect. And it's odd that you perform a bunch of work in the body of the handle let expression only to bind it to 0... do you mean handle or recieveData to be functions? If so maybe you intended something more like
let handle socket = //make handle a function with socket an explicit dependency
let handler = socket.Accept()
let bytesRec = handler.Receive(bytes)
let data = Encoding.ASCII.GetString(bytes,0,bytesRec)
Console.WriteLine( "Text received : {0}", data)
Console.Read() |> ignore //probably you are using Read to wait for user interaction to continue, but just ignore the result (returning unit) instead of returning 0
[<EntryPoint>]
let Main (args : string[]) =
let start = startServer args.[0]
Console.Read()