Compare commits

..

10 Commits

Author SHA1 Message Date
Kinch 337b83450f rr: can display ms form results 2023-09-27 14:21:41 +02:00
Kinch 9ba4dee953 rr: add rect_xyxy 2023-09-27 11:46:17 +02:00
Kinch 9df43797a1 starting with rerun bindings 2023-09-27 11:26:53 +02:00
Kinch c85d762ecf add zip_sink 2023-09-27 10:42:31 +02:00
Kinch 98565b175c add walkdir source 2023-09-19 22:30:26 +02:00
Kinch b9b9fc393c rework but everything is dyn 2023-09-19 21:44:21 +02:00
Kinch 2e63947569 restart from scratch 2023-09-19 20:06:16 +02:00
Kinch cb6bce2ba5 working on zip writer 2023-09-19 19:57:12 +02:00
Kinch e96052c286 add with input stream 2023-09-17 21:49:37 +02:00
Kinch ca1dca8414 add source sinkd concept 2023-09-17 21:27:11 +02:00
25 changed files with 6645 additions and 170 deletions

6294
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
[workspace]
resolver = "2"
members = [
"lua_modules/filesystem"
"lua_modules/filesystem",
"lua_modules/rerun_lua"
]
[workspace.dependencies]
mlua = { version = "0.9.1", features = ["lua54", "module"] }
mlua = { version = "0.9.1", features = ["lua54", "module", "serde", "serialize"] }

View File

@ -5,6 +5,10 @@ run-fs: (lua "fs.example.lua")
build-filesystem: (_copy-so "dev" "filesystem")
deploy-fs: (_deploy "filesystem")
run-rr: (lua "rr.example.lua")
build-rr: (_copy-so "dev" "rerun_lua")
deploy-rr: (_deploy "rerun_lua")
lua file:
LUA_CPATH=c_modules/?.so lua lua/{{file}}

View File

@ -1,77 +1,13 @@
local fs = require("filesystem")
local dirs = fs.directory("/Users/kinch/Desktop/Rebuild World")
local root = fs.directory(".")
local FileTree = {foo = "bar"}
function FileTree:new(iterator)
local file_tree = {
iterator = iterator,
filters = {}
}
setmetatable(file_tree, self)
self.__index = self
return file_tree
string.starts_with = function(self, str)
return self:find('^' .. str) ~= nil
end
function FileTree:filter(filter_fn)
table.insert(self.filters, filter_fn)
return self
end
function FileTree:__call()
local next = self.iterator()
if next == nil then
return nil
end
for k,filter in pairs(self.filters) do
if (not filter(next)) then
return self()
for entry in root do
if not entry.rel_path:starts_with("%.") then
print(entry.rel_path)
end
end
return next
end
function is_dir(entry)
return entry:is_dir()
end
function starts_with(prefix)
return function(entry)
return entry.path:find("^"..prefix)
end
end
function does_not(predicate)
return function(...) return not predicate(...) end
end
local comic_dir = FileTree:new(fs.directory("."))
comic_dir:filter(is_dir)
for chapter_dir in comic_dir do
FileTree:new(fs.directory(chapter_dir)):filter(does_not(starts_with("./")))
end
--for dir in dirs do
-- if dir:is_dir() then
-- for sub_dir in fs.directory(dir.path) do
-- print(sub_dir)
-- end
-- end
--end
--for dir in dirs do
-- local files = dir:filter {
-- exclude = function(file)
-- return file.is_file and not file.basename:starts_with("._")
-- end
-- }
--
-- zip {
-- from = files,
-- into = dir.basename,
-- extension = "cbz",
-- }
--end

64
lua/rr.example.lua Normal file
View File

@ -0,0 +1,64 @@
local rr = require("rerun_lua")
function bbox(ms_ocr_bbox)
return rr.rect_xyxy {
ms_ocr_bbox[1],
ms_ocr_bbox[2],
ms_ocr_bbox[5],
ms_ocr_bbox[6],
}
end
function paragraphs(ms_form_result)
local result = {}
for _, paragraph in ipairs(ms_form_result.analyzeResult.paragraphs) do
for _, region in ipairs(paragraph.boundingRegions) do
table.insert(result, {
text = paragraph.content,
page = region.pageNumber,
bbox = bbox(region.polygon)
})
end
end
return result
end
function lines(ms_form_result)
local result = {}
for _, page in ipairs(ms_form_result.analyzeResult.pages) do
for _, line in ipairs(page.lines) do
table.insert(result, {
text = line.content,
page = page.pageNumber,
bbox = bbox(line.polygon)
})
end
end
return result
end
function words(ms_form_result)
local result = {}
for _, page in ipairs(ms_form_result.analyzeResult.pages) do
for _, word in ipairs(page.words) do
table.insert(result, {
text = word.content,
page = page.pageNumber,
bbox = bbox(word.polygon)
})
end
end
return result
end
local ms_form = rr.json("/Users/tbr/Desktop/ms_form.json")
local record = rr.recording("example-2")
record:image("54-0", "/Users/tbr/Desktop/00054-0.png")
record:text_objects("54-0/ms-forms/paragraphs",paragraphs(ms_form))
record:text_objects("54-0/ms-forms/lines",lines(ms_form))
record:text_objects("54-0/ms-forms/words",words(ms_form))

View File

@ -7,4 +7,7 @@ edition = "2021"
crate-type = ["cdylib"]
[dependencies]
thiserror = "1.0.48"
mlua = { workspace = true }
zip = "0.6"
walkdir = "2.4.0"

View File

@ -0,0 +1,41 @@
use crate::driver_filesystem::filesystem_resource::FilesystemResourceLocation;
use crate::resource::{DynResource, DynResourceLocation, Resource, ResourceLocation};
use crate::source::ResourceSource;
use std::fs::rename;
use std::io::Sink;
use std::path::PathBuf;
use walkdir::WalkDir;
pub struct DirectorySource {
location: String,
iter: walkdir::IntoIter,
}
impl DirectorySource {
pub fn open_dir(location: String) -> Self {
let iter = WalkDir::new(location.clone()).into_iter();
DirectorySource { location, iter }
}
}
impl ResourceSource for DirectorySource {
fn location(&self) -> DynResourceLocation {
Box::new(FilesystemResourceLocation::from(PathBuf::from(
self.location.clone(),
)))
}
}
impl Iterator for DirectorySource {
type Item = DynResourceLocation;
fn next(&mut self) -> Option<Self::Item> {
use crate::resource::ResourceLocation;
self.iter
.next()
.map(|entry| entry.unwrap())
.map(|entry| entry.path().strip_prefix("./").unwrap().to_path_buf())
.map(|entry| {
let loc = FilesystemResourceLocation::from(entry);
Box::new(loc) as Box<dyn ResourceLocation>
})
}
}

View File

@ -0,0 +1,18 @@
use crate::resource::ResourceLocation;
use std::path::PathBuf;
pub struct FilesystemResourceLocation {
path: PathBuf,
}
impl ResourceLocation for FilesystemResourceLocation {
fn location(&self) -> String {
self.path.display().to_string()
}
}
impl From<PathBuf> for FilesystemResourceLocation {
fn from(path: PathBuf) -> Self {
FilesystemResourceLocation { path }
}
}

View File

@ -0,0 +1,2 @@
pub mod directory_source;
pub mod filesystem_resource;

View File

@ -0,0 +1,8 @@
use crate::sink::ResourceSink;
use std::iter::Zip;
mod zip_zink;
pub struct ZipZink {}
impl ResourceSink for ZipZink {}

View File

@ -0,0 +1,16 @@
use mlua::prelude::{LuaError, LuaResult};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum FsError {
#[error("fs error happened: {msg}")]
GenericError { msg: String },
}
pub type Res<T = ()> = Result<T, FsError>;
impl From<FsError> for LuaError {
fn from(fs_error: FsError) -> Self {
LuaError::RuntimeError(fs_error.to_string())
}
}

View File

@ -1,11 +1,19 @@
mod types;
mod driver_filesystem;
mod driver_zip_archive;
mod error;
mod lua_bindings;
mod operations;
mod resource;
mod sink;
mod source;
use crate::types::file_tree::*;
use crate::source::DynResourceSource;
use driver_filesystem::directory_source::DirectorySource;
use mlua::prelude::*;
fn directory(lua: &Lua, path: String) -> LuaResult<DirectoryFileTreeIter> {
let read_dir = std::fs::read_dir(path).unwrap();
Ok(DirectoryFileTreeIter { read_dir })
fn directory(lua: &Lua, path: String) -> LuaResult<DynResourceSource> {
let source = DirectorySource::open_dir(path);
Ok(Box::new(source))
}
#[mlua::lua_module]

View File

@ -0,0 +1,5 @@
use crate::resource::DynResourceLocation;
use mlua::{MetaMethod, UserData, UserDataFields, UserDataMethods};
mod resource_bindings;
mod source_bindings;

View File

@ -0,0 +1,12 @@
use crate::resource::DynResourceLocation;
use mlua::{MetaMethod, UserData, UserDataFields, UserDataMethods};
impl UserData for DynResourceLocation {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("rel_path", |lua, this| Ok(this.location()))
}
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method_mut(MetaMethod::ToString, |lua, this, _: ()| Ok(this.location()));
}
}

View File

@ -0,0 +1,8 @@
use crate::source::DynResourceSource;
use mlua::{MetaMethod, UserData, UserDataMethods};
impl UserData for DynResourceSource {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method_mut(MetaMethod::Call, |lua, this, _: ()| Ok(this.next()));
}
}

View File

@ -0,0 +1 @@
mod operation_copy;

View File

@ -0,0 +1,4 @@
use crate::sink::DynResourceSink;
use crate::source::DynResourceSource;
pub fn copy_operation(from: DynResourceSource, to: DynResourceSink) {}

View File

@ -0,0 +1,17 @@
use crate::sink::ResourceSink;
use crate::source::ResourceSource;
/// Points to a resource. Think of it as a path.
pub trait ResourceLocation {
fn location(&self) -> String;
}
/// A concrete resource. Think of as a directory or a file
pub trait Resource {}
// A resource ready to be read. Think of it as a open file for reading
pub trait ResourceInputStream: std::io::Read {}
// A resource ready to be written. Think of it as a open file for reading
pub trait ResourceOutputStream: std::io::Write {}
pub type DynResource = Box<dyn Resource>;
pub type DynResourceLocation = Box<dyn ResourceLocation>;
pub type DynResourceInputStream = Box<dyn ResourceInputStream>;
pub type DynResourceOutputStream = Box<dyn ResourceOutputStream>;

View File

@ -0,0 +1,8 @@
// mod zip_sink;
use crate::resource::{Resource, ResourceInputStream};
pub trait ResourceSink {
// fn add_file(&mut self, input_stream: DynResourceInputStream) {}
}
pub type DynResourceSink = Box<dyn ResourceSink>;

View File

@ -0,0 +1,5 @@
use crate::resource::{DynResource, DynResourceLocation};
pub trait ResourceSource: Iterator<Item = DynResourceLocation> {
fn location(&self) -> DynResourceLocation;
}
pub type DynResourceSource = Box<dyn ResourceSource<Item = DynResourceLocation>>;

View File

@ -1,87 +0,0 @@
use crate::types::file_tree::ResourceType::{Directory, RegularFile};
use mlua::{MetaMethod, UserData, UserDataFields, UserDataMethods};
use std::fs::{DirEntry, FileType, ReadDir};
use std::path::PathBuf;
pub enum ResourceType {
Directory,
RegularFile,
}
impl From<FileType> for ResourceType {
fn from(file_type: FileType) -> Self {
if file_type.is_file() {
RegularFile
} else {
Directory
}
}
}
pub trait Resource {
fn path(&self) -> String;
fn file_type(&self) -> ResourceType;
fn is_dir(&self) -> bool {
if let Directory = self.file_type() {
true
} else {
false
}
}
fn is_file(&self) -> bool {
if let RegularFile = self.file_type() {
true
} else {
false
}
}
}
pub struct FileSystemResource {
path: PathBuf,
}
impl Resource for FileSystemResource {
fn path(&self) -> String {
self.path.display().to_string()
}
fn file_type(&self) -> ResourceType {
self.path.metadata().unwrap().file_type().into()
}
}
pub trait FileTreeIter<RES: Resource>: Iterator<Item = RES> {}
pub struct DirectoryFileTreeIter {
pub read_dir: ReadDir,
}
impl Iterator for DirectoryFileTreeIter {
type Item = FileSystemResource;
fn next(&mut self) -> Option<Self::Item> {
self.read_dir.next().map(|entry| entry.unwrap().into())
}
}
impl From<DirEntry> for FileSystemResource {
fn from(value: DirEntry) -> Self {
FileSystemResource { path: value.path() }
}
}
impl UserData for DirectoryFileTreeIter {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method_mut(MetaMethod::Call, |lua, dir_iter, _: ()| Ok(dir_iter.next()));
}
}
impl UserData for FileSystemResource {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("path", |lua, fsr| Ok(fsr.path.display().to_string()))
}
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::ToString, |lua, fsr, _: ()| Ok(fsr.path()));
methods.add_method("is_dir", |lua, fsr, _: ()| Ok(fsr.is_dir()));
methods.add_method("is_file", |lua, fsr, _: ()| Ok(fsr.is_file()));
}
}

View File

@ -1 +0,0 @@
pub mod file_tree;

View File

@ -0,0 +1,15 @@
[package]
name = "rerun_lua"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
image = { version = "0.24.7", features = ["png", "jpeg", "tiff"] }
mlua = { workspace = true }
rerun = "0.8.2"
serde_json = "1.0.107"
serde = { version = "1.0.188", features = ["derive"] }

View File

@ -0,0 +1,99 @@
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use mlua::{AnyUserData, Function, MetaMethod, Table, TableExt, UserData, UserDataRef};
use mlua::prelude::*;
use rerun::{MsgSender, RecordingStream, RecordingStreamBuilder};
use rerun::components::{Rect2D, Tensor, Vec4D};
use serde::{Deserialize, Serialize};
#[derive(Debug)]
pub struct TextObject {
pub text: String,
pub bbox: Rect2D,
}
impl UserData for TextObject {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::ToString, |_lua, this, _:()| {
Ok(format!("{:?}", this))
})
}
}
impl<'lua> FromLua<'lua> for TextObject {
fn from_lua(value: LuaValue<'lua>, lua: &'lua Lua) -> LuaResult<Self> {
let table = value.as_table().ok_or(LuaError::RuntimeError("invalid args for text_object".to_string()))?;
let rect = table.get::<_, UserDataRef<Rect2D>>("bbox")?.clone();
Ok(TextObject {
text: table.get("text")?,
bbox: rect
})
}
}
fn json(lua: &Lua, path: String) -> LuaResult<LuaValue> {
let file = File::open(path.as_str())
.map_err(|error| LuaError::RuntimeError(format!("could not open json path: {path}. Error: {error}")))?;
let reader = BufReader::new(file);
let json_value: serde_json::Value = serde_json::from_reader(reader)
.map_err(|error| LuaError::RuntimeError(format!("could not parse json at: {path}. Error: {error}")))?;
lua.to_value(&json_value)
}
fn recording(lua: &Lua, name: String) -> LuaResult<AnyUserData> {
let stream = RecordingStreamBuilder::new(name)
.connect(rerun::default_server_addr(), None)
.map_err(|err| LuaError::RuntimeError(err.to_string()))?;
lua.create_any_userdata(stream)
}
fn rect_xyxy(lua: &Lua, points: [f32;4]) -> LuaResult<AnyUserData> {
let rect = Rect2D::XYXY(Vec4D(points).into());
lua.create_any_userdata(rect)
}
fn register_bindings(lua: &Lua) -> LuaResult<()> {
lua.register_userdata_type::<Rect2D>(|reg| {
reg.add_meta_method(MetaMethod::ToString, |lua, this, _:()| Ok(format!("{:?}", this)))
})?;
lua.register_userdata_type::<RecordingStream>(|reg|{
reg.add_method("image", |lua, this, (entity_path, image_path): (String,String)| {
let image_tensor = Tensor::from_image_file(PathBuf::from(image_path.as_str()).as_path())
.map_err(|error| LuaError::RuntimeError(format!("Could not read image file {image_path}. Error: {error}")))?;
MsgSender::new(entity_path)
.with_timeless(true)
.with_component(&[image_tensor])
.map_err(|error| LuaError::RuntimeError(format!("Could not send message: {}", error)))?
.send(this)
.map_err(|error| LuaError::RuntimeError(format!("Could not send message {error}")))?;
Ok(())
});
reg.add_method("text_objects", |lua, this, (entity_path, objects): (String, Vec<TextObject>)| {
let rects: Vec<Rect2D> = objects.into_iter()
.map(|t| t.bbox)
.collect();
MsgSender::new(entity_path)
.with_timeless(true)
.with_component(rects.as_slice())
.map_err(|error| LuaError::RuntimeError(format!("Could not send message: {}", error)))?
.send(this)
.map_err(|error| LuaError::RuntimeError(format!("Could not send message {error}")))?;
Ok(())
})
})?;
Ok(())
}
#[mlua::lua_module]
fn rerun_lua(lua: &Lua) -> LuaResult<LuaTable> {
register_bindings(lua)?;
let exports = lua.create_table()?;
exports.set("recording", lua.create_function(recording)?)?;
exports.set("json", lua.create_function(json)?)?;
exports.set("rect_xyxy", lua.create_function(rect_xyxy)?)?;
Ok(exports)
}