Skip to content

Commit 8f4f4e9

Browse files
authored
DataLoaders 2: add text-based DataLoader (.txt, .md) (#4518)
What the title says. ![image](https://github.com/rerun-io/rerun/assets/2910679/68f2e499-f4df-4e75-95f6-0ed7f479c5e6) Checks: - [x] `cargo r -p rerun-cli --no-default-features --features native_viewer -- examples/assets/example.{glb,gltf,obj,jpg,png,rrd,txt,md}` - [x] Native: `File > Open > examples/assets/*` - [x] Native: `Drag-n-drop > examples/assets/*` - [x] Web: `File > Open > examples/assets/*` - [x] Web: `Drag-n-drop > examples/assets/*` --- Part of a series of PRs to make it possible to load _any_ file from the local filesystem, by any means, on web and native: - #4516 - #4517 - #4518 - #4519 - #4520 - #4521 - TODO: register custom loaders - TODO: high level docs and guides for everything related to loading files
1 parent b51df6a commit 8f4f4e9

File tree

12 files changed

+115
-13
lines changed

12 files changed

+115
-13
lines changed

.typos.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ extend-exclude = [
77
".typos.toml",
88
"crates/re_ui/data/design_tokens.json",
99
"crates/re_ui/src/design_tokens.rs",
10+
"examples/assets",
1011
]
1112

1213

crates/re_data_source/src/data_loader/loader_archetype.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,15 @@ impl DataLoader for ArchetypeLoader {
9696
entity_path,
9797
contents.into_owned(),
9898
)?);
99-
};
99+
} else if crate::SUPPORTED_TEXT_EXTENSIONS.contains(&extension.as_str()) {
100+
re_log::debug!(?filepath, loader = self.name(), "Loading text document…",);
101+
rows.extend(load_text_document(
102+
filepath,
103+
timepoint,
104+
entity_path,
105+
contents.into_owned(),
106+
)?);
107+
}
100108

101109
for row in rows {
102110
if tx.send(row.into()).is_err() {
@@ -153,3 +161,25 @@ fn load_image(
153161

154162
Ok(rows.into_iter())
155163
}
164+
165+
fn load_text_document(
166+
filepath: std::path::PathBuf,
167+
timepoint: TimePoint,
168+
entity_path: EntityPath,
169+
contents: Vec<u8>,
170+
) -> Result<impl ExactSizeIterator<Item = DataRow>, DataLoaderError> {
171+
re_tracing::profile_function!();
172+
173+
let rows = [
174+
{
175+
let arch = re_types::archetypes::TextDocument::from_file_contents(
176+
contents,
177+
re_types::components::MediaType::guess_from_path(filepath),
178+
)?;
179+
DataRow::from_archetype(RowId::new(), timepoint, entity_path, &arch)?
180+
},
181+
//
182+
];
183+
184+
Ok(rows.into_iter())
185+
}

crates/re_data_source/src/data_loader/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use re_log_types::{ArrowMsg, DataRow, LogMsg};
2626
/// - [`ArchetypeLoader`] for:
2727
/// - [3D models]
2828
/// - [Images]
29+
/// - [Text files]
2930
///
3031
/// ## Execution
3132
///
@@ -38,6 +39,7 @@ use re_log_types::{ArrowMsg, DataRow, LogMsg};
3839
/// [Rerun extensions]: crate::SUPPORTED_RERUN_EXTENSIONS
3940
/// [3D models]: crate::SUPPORTED_MESH_EXTENSIONS
4041
/// [Images]: crate::SUPPORTED_IMAGE_EXTENSIONS
42+
/// [Text files]: crate::SUPPORTED_TEXT_EXTENSIONS
4143
//
4244
// TODO(#4525): `DataLoader`s should support arbitrary URIs
4345
// TODO(#4526): `DataLoader`s should be exposed to the SDKs

crates/re_data_source/src/lib.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44
//! - Over WebSockets
55
//! - From disk
66
//!
7-
//! Also handles different file types:
8-
//!
9-
//! - .rrd
10-
//! - images
11-
//! - meshes
7+
//! Also handles different file types: rrd, images, text files, 3D models, point clouds…
128
139
mod data_loader;
1410
mod data_source;
@@ -51,12 +47,16 @@ pub const SUPPORTED_MESH_EXTENSIONS: &[&str] = &["glb", "gltf", "obj"];
5147

5248
pub const SUPPORTED_RERUN_EXTENSIONS: &[&str] = &["rrd"];
5349

50+
// TODO(#4555): Add catch-all builtin `DataLoader` for text files
51+
pub const SUPPORTED_TEXT_EXTENSIONS: &[&str] = &["txt", "md"];
52+
5453
/// All file extension supported by our builtin [`DataLoader`]s.
5554
pub fn supported_extensions() -> impl Iterator<Item = &'static str> {
5655
SUPPORTED_RERUN_EXTENSIONS
5756
.iter()
5857
.chain(SUPPORTED_IMAGE_EXTENSIONS)
5958
.chain(SUPPORTED_MESH_EXTENSIONS)
59+
.chain(SUPPORTED_TEXT_EXTENSIONS)
6060
.copied()
6161
}
6262

@@ -65,4 +65,5 @@ pub fn is_supported_file_extension(extension: &str) -> bool {
6565
SUPPORTED_IMAGE_EXTENSIONS.contains(&extension)
6666
|| SUPPORTED_MESH_EXTENSIONS.contains(&extension)
6767
|| SUPPORTED_RERUN_EXTENSIONS.contains(&extension)
68+
|| SUPPORTED_TEXT_EXTENSIONS.contains(&extension)
6869
}

crates/re_types/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ features = ["all"]
2323
default = []
2424

2525
## All features except `testing`.
26-
all = ["ecolor", "glam", "serde"]
26+
all = ["ecolor", "glam", "image", "serde"]
2727

2828
## Enables the `datagen` module, which exposes a number of tools for generating random data for
2929
## tests and benchmarks.

crates/re_types/src/archetypes/image_ext.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use image::ImageFormat;
2-
31
use crate::{
42
datatypes::TensorData,
53
image::{find_non_empty_dim_indices, ImageConstructionError},
@@ -49,6 +47,7 @@ impl Image {
4947
/// Creates a new [`Image`] from a file.
5048
///
5149
/// The image format will be inferred from the path (extension), or the contents if that fails.
50+
#[cfg(feature = "image")]
5251
#[cfg(not(target_arch = "wasm32"))]
5352
#[inline]
5453
pub fn from_file_path(filepath: impl AsRef<std::path::Path>) -> anyhow::Result<Self> {
@@ -61,10 +60,11 @@ impl Image {
6160
/// Creates a new [`Image`] from the contents of a file.
6261
///
6362
/// If unspecified, the image format will be inferred from the contents.
63+
#[cfg(feature = "image")]
6464
#[inline]
6565
pub fn from_file_contents(
6666
contents: Vec<u8>,
67-
format: Option<ImageFormat>,
67+
format: Option<image::ImageFormat>,
6868
) -> anyhow::Result<Self> {
6969
let format = if let Some(format) = format {
7070
format

crates/re_types/src/archetypes/mod.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use crate::components::MediaType;
2+
3+
use super::TextDocument;
4+
5+
impl TextDocument {
6+
/// Creates a new [`TextDocument`] from a utf8 file.
7+
///
8+
/// The media type will be inferred from the path (extension), or the contents if that fails.
9+
#[cfg(not(target_arch = "wasm32"))]
10+
pub fn from_file_path(filepath: impl AsRef<std::path::Path>) -> anyhow::Result<Self> {
11+
use anyhow::Context as _;
12+
13+
let filepath = filepath.as_ref();
14+
let contents = std::fs::read(filepath)
15+
.with_context(|| format!("could not read file contents: {filepath:?}"))?;
16+
Self::from_file_contents(contents, MediaType::guess_from_path(filepath))
17+
.with_context(|| format!("could not parse file contents: {filepath:?}"))
18+
}
19+
20+
/// Creates a new [`TextDocument`] from the contents of a utf8 file.
21+
///
22+
/// If unspecified, the media type will be inferred from the contents.
23+
#[inline]
24+
pub fn from_file_contents(
25+
contents: Vec<u8>,
26+
media_type: Option<impl Into<MediaType>>,
27+
) -> anyhow::Result<Self> {
28+
let media_type = media_type.map(Into::into);
29+
let media_type = MediaType::or_guess_from_data(media_type, &contents);
30+
Ok(Self {
31+
text: String::from_utf8(contents)?.into(),
32+
media_type,
33+
})
34+
}
35+
}

docs/cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"version": "0.2",
44
"usePnP": true,
55
"ignorePaths": [
6-
"node_modules/**"
6+
"node_modules/**",
7+
"../examples/assets/**"
78
],
89
"ignoreWords": [
910
"-useb",

examples/assets/example.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Huge
2+
3+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque eleifend mi eget tellus pellentesque, sit amet ultricies tortor iaculis. Pellentesque viverra ipsum ut nisl rutrum maximus. Nunc vehicula lectus quis lacinia condimentum. Suspendisse lobortis mattis nisl, id egestas dui condimentum vitae. Integer lacus quam, commodo eget pretium at, scelerisque ac diam. Donec consectetur mauris felis. Proin pharetra, velit in venenatis facilisis, nunc diam blandit justo, sit amet laoreet ex nunc ut mi. Morbi ut tincidunt leo, eu maximus urna.
4+
5+
## Big
6+
7+
Aenean odio enim, elementum non nibh at, lacinia pretium elit. Quisque sit amet porta metus. Nunc in arcu turpis. Sed non tristique tellus, eget ultrices arcu. In rhoncus nibh in dolor pellentesque, id suscipit sem volutpat. Suspendisse condimentum tempor ante, sed rutrum eros viverra vitae. Sed vitae vestibulum eros, eu auctor velit. Praesent a efficitur elit. Nulla finibus porttitor tortor nec semper.
8+
9+
Nulla fermentum est ac convallis bibendum. Ut cursus, libero at sollicitudin laoreet, nunc ante aliquam dolor, quis malesuada mi ligula a sapien. Pellentesque sollicitudin odio a tempor tempus. Ut finibus nulla eget placerat hendrerit. Aenean eu arcu metus. Aliquam erat volutpat. Sed in ullamcorper mauris. Ut sollicitudin nisi fermentum, molestie justo eu, malesuada magna. Proin semper nisi sit amet pulvinar lacinia. Etiam purus magna, accumsan facilisis tellus eu, tincidunt dignissim dui.
10+
11+
### Less big
12+
13+
In massa arcu, finibus congue vulputate quis, pulvinar ac est. Morbi felis nibh, cursus ut mi id, rutrum rutrum est. Cras interdum enim non ipsum ornare commodo. Ut blandit, dui quis efficitur eleifend, urna nisl cursus metus, at placerat tortor orci et sem. Morbi sodales felis sed mattis tempus. Vivamus scelerisque dignissim mi. Etiam elementum mattis turpis, id porttitor arcu. Maecenas dui ipsum, scelerisque non molestie eu, hendrerit in justo. In hac habitasse platea dictumst. Curabitur faucibus hendrerit turpis quis gravida.
14+
15+
Etiam velit mauris, varius in aliquam eu, malesuada eu massa. Nulla eu arcu in velit bibendum volutpat. Nulla sollicitudin lectus nisi, ac efficitur nibh consectetur vitae. Fusce a placerat turpis. Nullam tincidunt sed nulla sed vulputate. In id pharetra libero, congue aliquet justo. In laoreet, odio a interdum fermentum, leo orci efficitur turpis, at tempus diam sem quis diam. Vestibulum ultricies urna eget mi dignissim convallis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla ut gravida ante, eget sodales metus. Integer pellentesque tempus magna, a scelerisque mi suscipit sed. Aenean sed malesuada ex.
16+
17+
#### Tiny
18+
19+
```rust
20+
"with some code!"
21+
```

0 commit comments

Comments
 (0)