From aa401bc0d68420d301931602b31cac2892ecc15d Mon Sep 17 00:00:00 2001 From: Tomasz Rejowski <34059895+Arcticae@users.noreply.github.com> Date: Fri, 12 Apr 2024 10:17:30 +0200 Subject: [PATCH] Move file reading docs to cairo (#1997) ## Checklist - [x] Linked relevant issue - [x] Updated relevant documentation - [x] Added relevant tests - [x] Performed self-review of the code - [x] Added changes to `CHANGELOG.md` --------- Co-authored-by: Kamil Jankowski Co-authored-by: Piotr Magiera <56825108+piotmag769@users.noreply.github.com> --- docs/src/appendix/snforge-library/fs.md | 94 +++++++++++++++++-- .../appendix/snforge-library/fs/parse_json.md | 66 ------------- .../appendix/snforge-library/fs/parse_txt.md | 58 ------------ .../appendix/snforge-library/fs/read_json.md | 47 ---------- .../appendix/snforge-library/fs/read_txt.md | 40 -------- snforge_std/src/fs/file_operations.cairo | 14 ++- 6 files changed, 101 insertions(+), 218 deletions(-) delete mode 100644 docs/src/appendix/snforge-library/fs/parse_json.md delete mode 100644 docs/src/appendix/snforge-library/fs/parse_txt.md delete mode 100644 docs/src/appendix/snforge-library/fs/read_json.md delete mode 100644 docs/src/appendix/snforge-library/fs/read_txt.md diff --git a/docs/src/appendix/snforge-library/fs.md b/docs/src/appendix/snforge-library/fs.md index e0bd64bb19..d5c2ee1acc 100644 --- a/docs/src/appendix/snforge-library/fs.md +++ b/docs/src/appendix/snforge-library/fs.md @@ -2,9 +2,91 @@ Module containing functions for interacting with the filesystem. -* [`read_txt`](fs/read_txt.md) - reads and parses plain text file content into an array of felts -* [`parse_txt`](fs/parse_txt.md) - parses plain text file content and tries to deserialize it into the - specified type -* [`read_json`](fs/read_json.md) - reads and parses json file content into an array of felts -* [`parse_json`](fs/parse_json.md) - parses json file content and tries to deserialize it into the specified - type \ No newline at end of file +## `File` +``` +trait FileTrait { + fn new(path: ByteArray) -> File; +} +``` + +## `FileParser` +```rust +trait FileParser> { + fn parse_txt(file: @File) -> Option; + fn parse_json(file: @File) -> Option; +} +``` + +## `read_txt` & `read_json` +```rust +fn read_txt(file: @File) -> Array; +fn read_json(file: @File) -> Array; +``` + + +## File format +Some rules have to be checked when providing a file for snforge, in order for correct parsing behavior. +Different ones apply for JSON and plain text files. + +### Plain text files +- Elements have to be separated with newlines +- Elements have to be either: + - integers in range of `[0, P)` where P is [`Cairo Prime`](https://book.cairo-lang.org/ch02-02-data-types.html?highlight=prime#felt-type) either in decimal or `0x` prefixed hex format + - single line short strings (`felt252`) of length `<=31` surrounded by `''` i.e., `'short string'`, new lines can be used with `\n` and `'` with `\'` + - single line strings (`ByteArray`) surrounded by `""` i.e., `"very very very very loooooong string"`, new lines can be used with `\n` and `"` with `\"` + + +### JSON files +- Elements have to be either: + - integers in range of `[0, P)` where P is [`Cairo Prime`](https://book.cairo-lang.org/ch02-02-data-types.html?highlight=prime#felt-type) + - single line strings (`ByteArray`) i.e. `"very very very very loooooong string"`, new lines can be used with `\n` and `"` with `\"` + - array of integers or strings fulfilling the above conditions + +> ⚠️ **Warning** +> +> A JSON object is an unordered data structure. To make reading JSONs deterministic, the values are read from the JSON in an order that is alphabetical in respect to JSON keys. +> Nested JSON values are sorted by the flattened format keys `(a.b.c)`. + + +## Example + +For example, this plain text file content: +```txt +1 +2 +'hello' +10 +"world" +``` +or this JSON file content: +```json +{ + "a": 1, + "nested": { + "b": 2, + "c": 448378203247 + }, + "d": 10, + "e": "world" +} +``` + +(note that short strings cannot be used in JSON file) + +could be parsed to the following struct in cairo, via `parse_txt`/`parse_json`: +```rust +A { + a: 1, + nested: B { + b: 2, + c: 'hello', + }, + d: 10, + e: "world" +} +``` + +or to an array, via `read_txt`/`read_json`: +```rust +array![1, 2, 'hello', 10, 0, 512970878052, 5] +``` \ No newline at end of file diff --git a/docs/src/appendix/snforge-library/fs/parse_json.md b/docs/src/appendix/snforge-library/fs/parse_json.md deleted file mode 100644 index a617426322..0000000000 --- a/docs/src/appendix/snforge-library/fs/parse_json.md +++ /dev/null @@ -1,66 +0,0 @@ -# `parse_json` - - -> `trait FileParser> { ->fn parse_json(file: @File) -> Option; -> }` - -Parses json file content and tries to deserialize it to type `T` that implements `Serde` trait. - -- `file` - a snapshot of an instance of the struct `File` that consists of the following fields: - - `path` - Cairo string representing a path to a file relative to a package root. - -> ⚠️ **Warning** -> -> A JSON object is an unordered data structure. To give it an order, the values in the array are sorted alphabetically by JSON keys. -To properly decode a JSON object, make sure the order of struct attributes aligns with the alphabetical order of the JSON keys. ->Nested JSON values are sorted by the flattened format keys `(a.b.c)`. - -```rust -use option::OptionTrait; -use serde::Serde; -use snforge_std::fs::{ FileTrait, FileParser }; - -#[derive(Serde, Drop)] -struct MyStruct { - a: u32, - b: felt252 -} - -#[test] -fn test_parse_json() { - let file = FileTrait::new("data/file.json"); - let my_struct = FileParser::::parse_json(@file).unwrap(); - // ... -} -``` - -## Accepted format -File content must have proper JSON Format with values satisfying the conditions: - - integers in range of `[0, P)` where P is [`Cairo Prime`](https://book.cairo-lang.org/ch02-02-data-types.html?highlight=prime#felt-type) - - strings of length `<=31` - - array of integers or strings fulfilling the above conditions - -For example, this file content: -```json -{ - "b": 1, - "a": 12, - "d": { - "e": 1234 - }, - "c": "123" -} -``` -could be parsed to the following struct: - -```rust -A { - a: 12, - b: 1, - c: "123" - d: B { - e: 1234 - } -} -``` diff --git a/docs/src/appendix/snforge-library/fs/parse_txt.md b/docs/src/appendix/snforge-library/fs/parse_txt.md deleted file mode 100644 index 55282e7c64..0000000000 --- a/docs/src/appendix/snforge-library/fs/parse_txt.md +++ /dev/null @@ -1,58 +0,0 @@ -# `parse_txt` - - -> `trait FileParser> { ->fn parse_txt(file: @File) -> Option; -> }` - - -Parses plain text file content and tries to deserialize it to type `T` that implements `Serde` trait. - -- `file` - a snapshot of an instance of the struct `File` that consists of the following fields: - - `path` - Cairo string representing a path to a file relative to a package root. - -```rust -use option::OptionTrait; -use serde::Serde; -use snforge_std::fs::{ FileTrait, FileParser }; - -#[derive(Serde, Drop)] -struct MyStruct { - a: u32, - b: felt252 -} - -#[test] -fn test_parse_txt() { - let file = FileTrait::new("data/file.txt"); - let my_struct = FileParser::::parse_txt(@file).unwrap(); - // ... -} -``` -## Accepted format -File content must consists of elements that: -- have to be separated with newlines -- have to be either: - - integers in range of `[0, P)` where P is [`Cairo Prime`](https://book.cairo-lang.org/ch02-02-data-types.html?highlight=prime#felt-type) either in decimal or `0x` prefixed hex format - - single line strings of length `<=31` (new lines can be used with \n) - -For example, this file content: -```txt -1 -2 -hello -10 -world -``` -could be parsed to the following struct: -```rust -A { - a: 1, - nested: B { - b: 2, - c: 'hello', - }, - d: 10, - e: 'world' -} -``` diff --git a/docs/src/appendix/snforge-library/fs/read_json.md b/docs/src/appendix/snforge-library/fs/read_json.md deleted file mode 100644 index d811d7caa1..0000000000 --- a/docs/src/appendix/snforge-library/fs/read_json.md +++ /dev/null @@ -1,47 +0,0 @@ -# `read_json` - -> `fn read_json(file: @File) -> Array` - -Read and parse json file content to an array of felts. - -- `file` - a snapshot of an instance of the struct `File` that consists of the following fields: - - `path` - Cairo string representing a path to a file relative to a package root. - -> ⚠️ **Warning** -> -> A JSON object is an unordered data structure. To give it an order, the values in the array are sorted alphabetically by JSON keys. Therefore, the values in the array are sorted alphabetically by JSON key. -> Nested JSON values are sorted by the flattened format keys `(a.b.c)`. - -```rust -use snforge_std::fs::{ FileTrait, read_json }; - -#[test] -fn test_read_json() { - let file = FileTrait::new("data/file.json"); - let content = read_json(@file); - // ... -} -``` - -## Accepted format -File content must have proper JSON Format with values satisfying the conditions: - - integers in range of `[0, P)` where P is [`Cairo Prime`](https://book.cairo-lang.org/ch02-02-data-types.html?highlight=prime#felt-type) - - single line strings (`ByteArray`) ie. `"very very very very loooooong string"`, new lines can be used with `\n` and `"` with `\"` - - array of integers or strings fulfilling the above conditions - -For example, this file content: -```json -{ - "b": 1, - "a": 12, - "d": { - "e": 1234 - }, - "c": 123 -} -``` -will be read to the following array: - -```rust -array![12, 1, 123, 1234] -``` diff --git a/docs/src/appendix/snforge-library/fs/read_txt.md b/docs/src/appendix/snforge-library/fs/read_txt.md deleted file mode 100644 index 5ac2b69287..0000000000 --- a/docs/src/appendix/snforge-library/fs/read_txt.md +++ /dev/null @@ -1,40 +0,0 @@ -# `read_txt` - -> `fn read_txt(file: @File) -> Array` - -Read and parses plain text file content to an array of felts. - -- `file` - a snapshot of an instance of the struct `File` that consists of the following fields: -- `path` - Cairo string representing a path to a file relative to a package root. - -```rust -use snforge_std::fs::{ FileTrait, read_txt }; - -#[test] -fn test_read_txt() { - let file = FileTrait::new("data/file.txt"); - let content = read_txt(@file); - // ... -} -``` - -## Accepted format -File content must consists of elements that: -- have to be separated with newlines -- have to be either: - - integers in range of `[0, P)` where P is [`Cairo Prime`](https://book.cairo-lang.org/ch02-02-data-types.html?highlight=prime#felt-type) either in decimal or `0x` prefixed hex format - - single line short strings (`felt252`) of length `<=31` surrounded by `''` ie. `'short string'`, new lines can be used with `\n` and `'` with `\'` - - single line strings (`ByteArray`) surrounded by `""` ie. `"very very very very loooooong string"`, new lines can be used with `\n` and `"` with `\"` - -For example, this file content: -```txt -1 -2 -'hello' -10 -'world' -``` -will be parsed to the following array: -```rust -array![1, 2, 'hello', 10, 'world'] -``` diff --git a/snforge_std/src/fs/file_operations.cairo b/snforge_std/src/fs/file_operations.cairo index b8ff19e2f1..6c505909bd 100644 --- a/snforge_std/src/fs/file_operations.cairo +++ b/snforge_std/src/fs/file_operations.cairo @@ -4,10 +4,12 @@ use super::super::_cheatcode::handle_cheatcode; #[derive(Drop, Clone)] struct File { - path: ByteArray // relative path + path: ByteArray } trait FileTrait { + /// Creates a file struct used for reading json / text + /// `path` - a path to file in ByteArray form, relative to the package root fn new(path: ByteArray) -> File; } @@ -17,6 +19,8 @@ impl FileTraitImpl of FileTrait { } } +/// `file` - a `File` struct to read text data from +/// Returns an array of felts read from the file, panics if read was not possible fn read_txt(file: @File) -> Array { let content = handle_cheatcode( cheatcode::<'read_txt'>(byte_array_as_felt_array(file.path).span()) @@ -35,6 +39,8 @@ fn read_txt(file: @File) -> Array { result } +/// `file` - a `File` struct to read json data from +/// Returns an array of felts read from the file, panics if read was not possible, or json was incorrect fn read_json(file: @File) -> Array { let content = handle_cheatcode( cheatcode::<'read_json'>(byte_array_as_felt_array(file.path).span()) @@ -54,7 +60,13 @@ fn read_json(file: @File) -> Array { } trait FileParser> { + /// Reads from the text file and tries to deserialize the result into given type with `Serde` + /// `file` - File instance + /// Returns an instance of `T` if deserialization was possible fn parse_txt(file: @File) -> Option; + /// Reads from the json file and tries to deserialize the result into given type with `Serde` + /// `file` - File instance + /// Returns an instance of `T` if deserialization was possible fn parse_json(file: @File) -> Option; }