Code Monkey home page Code Monkey logo

recap's Introduction

recap Main Software License crates.io Released API docs Master API docs

deserialize named capture groups into typesafe structs

Recap is provides what envy provides for environment variables, for named capture groups. Named regex capture groups are like any other regex capture group but have the extra property that they are associated with name. i.e (?P<name-of-capture-group>some-pattern)

๐Ÿค” who is this for

You may find this crate useful for cases where your application needs to extract information from string input provided by a third party that has a loosely structured format.

A common usecase for this is when you are dealing with log file data that was not stored in a particular structured format like JSON, but rather in a format that can be represented with a pattern.

You may also find this useful parsing other loosely formatted data patterns.

This crate would be less appropriate for cases where your input is provided in a more structured format, like JSON. I recommend using a crate like serde-json for those cases instead.

๐Ÿ“ฆ install

Add the following to your Cargo.toml file.

[dependencies]
recap = "0.1"

๐Ÿคธ usage

A typical recap usage looks like the following. Assuming your Rust program looks something like this...

๐Ÿ’ก These examples use Serde's derive feature

use recap::Recap;
use serde::Deserialize;
use std::error::Error;

#[derive(Debug, Deserialize, Recap)]
#[recap(regex = r#"(?x)
    (?P<foo>\d+)
    \s+
    (?P<bar>true|false)
    \s+
    (?P<baz>\S+)
  "#)]
struct LogEntry {
    foo: usize,
    bar: bool,
    baz: String,
}

fn main() -> Result<(), Box<dyn Error>> {
    let logs = r#"1 true hello
  2 false world"#;

    for line in logs.lines() {
        let entry: LogEntry = line.parse()?;
        println!("{:#?}", entry);
    }

    Ok(())
}

๐Ÿ‘ญ Consider this crate a cousin of envy, a crate for deserializing environment variables into typesafe structs.

Doug Tangren (softprops) 2019

recap's People

Contributors

boringcactus avatar cuviper avatar softprops avatar whoisdavid avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

recap's Issues

#[derive(Recap)] doesn't compose

๐Ÿ’ก Feature description

Currently the code generated by #[derive(Recap)] doesn't seem to be able to be composed in any manner. Ideally, I would more or less expect that fields of types with #[derive(Recap)] ought to be able to be parsed just like primitives and builtin types.

๐Ÿ’ป Basic example

#[derive(Debug, Deserialize, Recap)]
#[recap(regex = r#"(?P<quantity>\d+) (?P<name>\w+)"#)]
struct Chemical {
    quantity: u32,
    name: String,
}

#[derive(Debug, Deserialize, Recap)]
#[recap(regex = r#"(?P<inner>\d+ \w+)"#)]
struct Wrapper {
    inner: Chemical,
}

fn main() {
    // ok
    "1 FUEL".parse::<Chemical>().unwrap();

    // Err(Custom("invalid type: string "1 FUEL", expected struct Chemical"))
    "1 FUEL".parse::<Wrapper>().unwrap();
}

support option type

I tried to write something like this

๐Ÿ’ป Basic example

use recap::Recap;
use serde::Deserialize;
use std::error::Error;

#[derive(Debug, Deserialize, Recap)]
#[recap(regex = r#"(?x)
    (?P<foo>\d+)
    \s+
    (?P<bar>true|false)
    \s+
    (?P<baz>\S+)
  "#)]
struct LogEntry {
    foo: usize,
    bar: bool,
    baz: Option<String>,
}

fn main() -> Result<(), Box<dyn Error>> {
    let logs = r#"1 true  
    2 false world"#;

    for line in logs.lines() {
        let entry: LogEntry = line.parse()?;
        println!("{:#?}", entry);
    }

    Ok(())
}

Error: Custom("No captures resolved in string '1 true '")

Document an example with enum

I'm learning Rust and this library is extremely useful for quick parsing of string data. However I've been stuck trying to parse a value which should be an enum; something like these strings:

R ff0000
G 00ff00
B 0000ff

My code looks like this:

use recap::Recap;
use serde::Deserialize;

#[derive(Deserialize, Recap)]
#[recap(regex = r#"(?P<dir>\w) (?P<code>\w+)"#)]
struct Config {
    type: Color,
    code: String,
}

#[derive(Debug, Deserialize)]
enum Color {
    R,
    G,
    B,
}

I have even tried with a FromStr implementation, but I'm really blindly trying things because of being too new to the ecosystem and not being able to figure out what direction I should take:

impl FromStr for Color {
    type Err = ();
    fn from_str(s: &str) -> Result<Color, ()> {
        match s {
            "R" => Ok(Color::R),
            "G" => Ok(Color::G),
            "B" => Ok(Color::B),
            _ => Err(()),
        }
    }
}

What I'd request is to extend the documentation if recap can be used for this use case; and otherwise a comment about it, so future beginners don't spend too much time trying to make it work, like me :-)

This type alias takes 1 generic argument but 2 generic arguments were supplied

I am getting the following error for the basic example. What am I doing wrong?

this type alias takes 1 generic argument but 2 generic arguments were supplied, expected 1 generic argument
10 | #[derive(Debug, Deserialize, Recap)]
   |                              ^^^^^
   |                              |
   |                              expected 1 generic argument
   |                              help: remove this generic argument
   |

๐Ÿ‘Ÿ Steps to reproduce

#[derive(Debug, Deserialize, Recap)]
#[recap(regex = r#"(?x)
    (?P<foo>\d+)  
    \s+ 
    (?P<bar>true|false)
    \s+
    (?P<baz>\S+) 
  "#)]
struct LogEntry {
    foo: usize,
    bar: bool,
    baz: String,
}

๐ŸŒ Your environment

Rust (Windows) 1.67.1

recap version:
0.1.2

more usable representation of errors

๐Ÿ’ก Feature description

the current design was an mvp with the error being an alias for envy::Error. This has the drawback in that its not currently possible in to destructure a type alias of an enum on stable rust. lets just create a custom error that has good From impls

๐Ÿ’ป Basic example

RFE: Capture borrowed types

๐Ÿ’ก Feature description

It would be nice to be able to capture referenced data, like a more general Deserialize<'de> rather than just DeserializeOwned.

I realize that FromStr can't borrow data, since there's no lifetime parameter to use in relation to Self, but maybe there could be a trait Recap<'s> which does permit borrowing. I would think recap::from_captures could just use a 'de parameter for D: Deserialize<'de>.

๐Ÿ’ป Basic example

I tried to write something like this for Advent of Code 2015 day 9:

#[derive(Deserialize, Recap)]
#[recap(regex = r"(?P<a>\w+) to (?P<b>\w+) = (?P<distance>\d+)")]
struct Distance<'a> {
    a: &'a str,
    b: &'a str,
    distance: u32,
}
error: implementation of `_IMPL_DESERIALIZE_FOR_Distance::_serde::Deserialize` is not general enough
[...]
   = note: `Distance<'_>` must implement `_IMPL_DESERIALIZE_FOR_Distance::_serde::Deserialize<'0>`, for any lifetime `'0`
   = note: but `Distance<'_>` actually implements `_IMPL_DESERIALIZE_FOR_Distance::_serde::Deserialize<'1>`, for some specific lifetime `'1`

It's not a big deal to use String instead in this case, since there aren't very many inputs overall, but it seems like a borrowed &str should be possible.

Validate regex at compile time

๐Ÿ’ก Feature description

Compile regex at derive time and verify capture count matches field count of struct

๐Ÿ’ป Basic example

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.