Skip to content

Commit

Permalink
support interpretation parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
emanueldima committed Mar 13, 2024
1 parent 3451638 commit 865daff
Show file tree
Hide file tree
Showing 33 changed files with 481 additions and 167 deletions.
24 changes: 18 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@

# Hial

Hial is a general purpose data API and CLI tool. It is a programmatic interface to different types of data represented in an uniform manner (a general tree/graph structure). This makes the data easy to read, explore and modify using a small number of functions. Hial proposes a relatively simple mental model, suitable for most use cases, which improves the user comfort and speed.
Hial is a general purpose data API and CLI tool. It is a programmatic interface to different types of data represented as uniform tree structures. This makes the data easy to read, explore and modify using a small number of functions. Hial proposes a relatively simple mental model, suitable for most use cases, which improves the user comfort and speed.

The types of data that can be supported by this API are the file system, configuration files (json, yaml, toml), markup files (xml, html), programs written in various programming languages, operating system configurations and runtime parameters, database tables and records, etc.

The API can be seen as an generalization of the concepts behind xpath, json path, file system path, and other similar path languages. It is a concise way to express data operations and transformations which are common in programming and system administration.
The path API can be seen as an generalization of the concepts behind xpath, json path, file system path, and other similar path languages. It is a concise way to express data searches common in programming and system administration.

:warning: Hial is **currently under construction.** Some things don't work yet and some things will change.

### What can it do?

##### 1. Select or search for precise pieces of data in a structured way.
##### 1. Select or search for pieces of data in a structured way.

Print a value embedded in a json file or from a url that returns json or xml data:

```bash
hial './config.json^json/services/webapp'
hial 'http://www.phonetik.uni-muenchen.de/cgi-bin/BASRepository/oaipmh/oai.pl^http^xml'
hial './examples/productiondump.json^json/stacks/*/services'
hial 'http://api.github.com^http^json/rate_limit_url^http^json/resources/core'
hial 'http://www.phonetik.uni-muenchen.de/cgi-bin/BASRepository/oaipmh/oai.pl^http^xml'
```

<!-- Print all questions that have no answer entities in a json file:
Expand Down Expand Up @@ -55,6 +55,7 @@ Print the structure of a rust file (struct, enum, type, functions) as a tree:
```bash
hial './src/tests/rust.rs^rust/**[#type^split["_"]/[-1]=="item"]/*[name|parameters|return_type]'
# 🚧 todo: search results as tree
# 🚧 todo: boolean filter combinator
```

##### 2. Modify data selected as above.
Expand All @@ -63,7 +64,7 @@ Change the default mysql port systemwide:
```bash
# shell
hial '/etc/mysql/my.cnf^fs[w]^ini/mysqld/port = 3307'
# 🚧 todo: rw parameter for fs interpretation
# 🚧 todo: assign operator
```

```bash
Expand Down Expand Up @@ -131,6 +132,17 @@ hial 'diff ./file.json^json^tree ./file.xml^xml^tree'
# 🚧 todo: support tree implementation and conversion
```

Diff two diff trees (e.g. check if two different commits make identical changes)

```bash
hial 'x = diff .^git/HEAD^fs .^git/HEAD~1^fs ;
y = diff .^git/branch1^fs .^git/branch1~1^fs ;
diff $x $y
'
# 🚧 todo: support diff
# 🚧 todo: support git interpretation
```

## Installation and usage

To test the examples or use the library from a shell, build the project: `cargo build --release`. Then run the `hial` command, e.g.: `hial 'http://api.github.com^http^json'`
Expand Down
4 changes: 1 addition & 3 deletions doc/issues.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# List of Todos and other Issues

- ^fs[w] ??
- dyn elevate cell as interpretation
- remove special elevategroup
- support ~
- support type selector: `hial './src/tests/rust.rs^rust/*[:function_item]'`
- add split(":") and regex interpretations
- /*[name|parameters|return_type] ??
Expand Down
1 change: 1 addition & 0 deletions examples/write2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-
2 changes: 1 addition & 1 deletion src/api/elevation_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{api::*, guard_ok, guard_some, warning};

use linkme::distributed_slice;

pub type ElevateParams = IndexMap<&'static str, OwnValue>;
pub type ElevateParams = IndexMap<OwnValue, OwnValue>;
pub type ElevateFn =
fn(source: Xell, target_interpretation: &'static str, params: &ElevateParams) -> Res<Xell>;
type TargetMap = IndexMap<&'static str, ElevateFn>;
Expand Down
163 changes: 129 additions & 34 deletions src/api/internal/elevation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use indexmap::IndexMap;

use crate::{
api::{interpretation::*, *},
implement_try_from_xell,
utils::{
ownrc::OwnRc,
ownrc::{OwnRc, ReadRc},
ownrcutils::{read, write},
},
};
Expand All @@ -27,7 +28,7 @@ pub struct Group {
kind: GroupKind,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum GroupKind {
Root,
Attr(usize),
Expand All @@ -40,23 +41,35 @@ pub struct Cell {
kind: CellKind,
}

#[derive(Debug)]
pub struct CellReader {
data: ReadRc<Data>,
kind: CellKind,
}

#[derive(Debug, Clone)]
enum CellKind {
Interpretation(usize),
Param(usize, usize),
DetachedParam(Box<(OwnValue, OwnValue)>),
}

implement_try_from_xell!(Cell, Elevation);

impl CellTrait for Cell {
type Group = Group;
type CellReader = Cell;
type CellReader = CellReader;
type CellWriter = Cell;

fn interpretation(&self) -> &str {
"interpretation"
}

fn read(&self) -> Res<Self::CellReader> {
Ok(self.clone())
Ok(CellReader {
data: read(&self.data)?,
kind: self.kind.clone(),
})
}

fn write(&self) -> Res<Self::CellWriter> {
Expand Down Expand Up @@ -90,42 +103,57 @@ impl CellTrait for Cell {
}
}

impl CellReaderTrait for Cell {
impl CellReaderTrait for CellReader {
fn ty(&self) -> Res<&str> {
match self.kind {
CellKind::Interpretation(_) => Ok("elevation"),
CellKind::Param(_, _) => Ok("param"),
CellKind::DetachedParam { .. } => Ok("param"),
}
}

fn value(&self) -> Res<Value> {
nores()
match &self.kind {
CellKind::Interpretation(_) => nores(),
CellKind::Param(ii, ip) => Ok(self
.data
.map
.get_index(*ii)
.ok_or_else(noerr)?
.1
.1
.get_index(*ip)
.ok_or_else(noerr)?
.1
.as_value()),
CellKind::DetachedParam(b) => Ok(b.1.as_value()),
}
}

fn label(&self) -> Res<Value> {
match self.kind {
match &self.kind {
CellKind::Interpretation(i) => {
let data = read(&self.data)?;
let entry = data.map.get_index(i).ok_or_else(noerr)?;
Ok(Value::Str(entry.0))
}
CellKind::Param(i, ip) => {
let data = read(&self.data)?;
let entry = data.map.get_index(i).ok_or_else(noerr)?;
entry
.1
.1
.get_index(ip)
.ok_or_else(noerr)
.map(|x| Value::Str(x.0))
Ok(Value::Str(self.data.map.get_index(*i).ok_or_else(noerr)?.0))
}
CellKind::Param(i, ip) => self
.data
.map
.get_index(*i)
.ok_or_else(noerr)?
.1
.1
.get_index(*ip)
.ok_or_else(noerr)
.map(|x| x.0.as_value()),
CellKind::DetachedParam(b) => Ok(b.0.as_value()),
}
}

fn index(&self) -> Res<usize> {
match self.kind {
CellKind::Interpretation(i) => Ok(i),
CellKind::Param(_, ip) => Ok(ip),
CellKind::DetachedParam { .. } => nores(),
}
}

Expand All @@ -135,14 +163,27 @@ impl CellReaderTrait for Cell {
}

impl CellWriterTrait for Cell {
fn set_value(&mut self, value: OwnValue) -> Res<()> {
match self.kind {
fn set_label(&mut self, v: OwnValue) -> Res<()> {
userres("cannot set labels on elevation cells")
}

fn set_value(&mut self, v: OwnValue) -> Res<()> {
match &mut self.kind {
CellKind::Interpretation(i) => userres("cannot set interpretation value"),
CellKind::Param(i, ip) => {
let mut data = write(&self.data)?;
let entry = data.map.get_index_mut(i).ok_or_else(noerr)?;
let param = entry.1 .1.get_index_mut(ip).ok_or_else(noerr)?;
*param.1 = value;
*write(&self.data)?
.map
.get_index_mut(*i)
.ok_or_else(noerr)?
.1
.1
.get_index_mut(*ip)
.ok_or_else(noerr)?
.1 = v;
Ok(())
}
CellKind::DetachedParam(b) => {
b.1 = v;
Ok(())
}
}
Expand Down Expand Up @@ -189,6 +230,42 @@ impl GroupTrait for Group {
// returns the correct type.
unimplemented!()
}

fn create(&self, label: Option<OwnValue>, value: Option<OwnValue>) -> Res<Self::Cell> {
if self.kind == GroupKind::Root {
return userres("cannot create new cells in interpretation root group");
}
if let GroupKind::Sub(_) = self.kind {
return userres("cannot create new cells in interpretation sub group");
}
if let Some(label) = label {
Ok(Cell {
data: self.data.clone(),
kind: CellKind::DetachedParam(Box::new((label, value.unwrap_or(OwnValue::None)))),
})
} else {
userres("cannot create new cells without a label")
}
}

fn add(&self, index: Option<usize>, cell: Self::Cell) -> Res<()> {
match self.kind {
GroupKind::Root => userres("cannot add cell to interpretaion root group"),
GroupKind::Sub(_) => userres("cannot add cell to interpretation sub group"),
GroupKind::Attr(i) => {
let mut data = write(&self.data)?;
let (target, (constructor, params)) =
data.map.get_index_mut(i).ok_or_else(noerr)?;
if let CellKind::DetachedParam(b) = cell.kind {
params.insert(b.0, b.1);
}
if let Some(index) = index {
data.map.move_index(i, index);
}
Ok(())
}
}
}
}

impl Group {
Expand Down Expand Up @@ -231,7 +308,7 @@ impl Group {
}
}
}
// debug!(
// println!(
// "new elevate group for {} -> {:?}",
// origin.interpretation(),
// map
Expand All @@ -251,19 +328,31 @@ impl Group {
data: self.data.clone(),
kind: CellKind::Interpretation(index),
};
Ok(new_xell(DynCell::from(cell), Some(data.origin.clone())))
Ok(Xell::new_from(
DynCell::from(cell),
Some(data.origin.clone()),
))
}
GroupKind::Attr(i) => {
let cell = Cell {
data: self.data.clone(),
kind: CellKind::Param(index, i),
};
Ok(new_xell(DynCell::from(cell), Some(data.origin.clone())))
Ok(Xell::new_from(
DynCell::from(cell),
Some(data.origin.clone()),
))
}
GroupKind::Sub(i) => {
let (target, (func, params)) = data.map.get_index(i).ok_or_else(noerr)?;
let cell = func(data.origin.clone(), target, params)?;
let (target, (constructor, params)) = data.map.get_index(i).ok_or_else(noerr)?;
let cell = constructor(data.origin.clone(), target, params)?;
cell.set_self_as_domain_root();

if let Some(w) = params.get(&Value::Str("w")) {
if w.as_value() == Value::Bool(true) || w.as_value() == Value::None {
cell.policy(WritePolicy::WriteBackOnDrop);
}
}
Ok(cell)
}
}
Expand All @@ -281,20 +370,26 @@ impl Group {
data: self.data.clone(),
kind: CellKind::Interpretation(entry.0),
};
Ok(new_xell(DynCell::from(cell), Some(data.origin.clone())))
Ok(Xell::new_from(
DynCell::from(cell),
Some(data.origin.clone()),
))
}
GroupKind::Attr(i) => {
let Some(entry) = data.map.get_index(i) else {
return nores();
};
let Some(entry) = entry.1 .1.get_full(label.as_cow_str().as_ref()) else {
let Some(entry) = entry.1 .1.get_full(&label) else {
return nores();
};
let cell = Cell {
data: self.data.clone(),
kind: CellKind::Param(i, entry.0),
};
Ok(new_xell(DynCell::from(cell), Some(data.origin.clone())))
Ok(Xell::new_from(
DynCell::from(cell),
Some(data.origin.clone()),
))
}
GroupKind::Sub(i) => {
userres("cannot use get to access interpretation root, use at instead")
Expand Down
7 changes: 6 additions & 1 deletion src/api/internal/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use crate::{api::interpretation::*, api::*};
use crate::{
api::{interpretation::*, *},
implement_try_from_xell,
};

implement_try_from_xell!(HErr, Error);

impl CellTrait for HErr {
type Group = HErr;
Expand Down
Loading

0 comments on commit 865daff

Please sign in to comment.