or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-operations.mdindex.mdlayers.mdservices.mdtypes.md

types.mddocs/

0

# Types and Error Handling

1

2

OpenDAL provides a comprehensive type system for storage-agnostic data handling, metadata management, and robust error handling. All types are designed for zero-copy operations and efficient memory usage.

3

4

```rust

5

use std::ops::RangeBounds;

6

use bytes::Bytes;

7

use chrono::{DateTime, Utc};

8

use flagset::{FlagSet};

9

```

10

11

## Capabilities

12

13

### Core Data Types

14

15

Primary data structures for file operations and metadata.

16

17

```rust { .api }

18

/// Efficient bytes container supporting both contiguous and non-contiguous data

19

pub struct Buffer;

20

21

impl Buffer {

22

/// Create buffer from bytes

23

pub fn from(data: impl Into<Bytes>) -> Self;

24

25

/// Create buffer from byte vector

26

pub fn from_vec(data: Vec<u8>) -> Self;

27

28

/// Create buffer from static byte slice

29

pub fn from_static(data: &'static [u8]) -> Self;

30

31

/// Get buffer length

32

pub fn len(&self) -> usize;

33

34

/// Check if buffer is empty

35

pub fn is_empty(&self) -> bool;

36

37

/// Convert to bytes

38

pub fn to_bytes(&self) -> Bytes;

39

40

/// Convert to byte vector (may require copying)

41

pub fn to_vec(&self) -> Vec<u8>;

42

43

/// Create a slice of the buffer within given range

44

pub fn slice(&self, range: impl RangeBounds<usize>) -> Self;

45

46

/// Truncate buffer to specified length

47

pub fn truncate(&mut self, len: usize);

48

49

/// Get current chunk as Bytes

50

pub fn current(&self) -> Bytes;

51

52

/// Get number of remaining chunks

53

pub fn count(&self) -> usize;

54

}

55

56

// Buffer implements AsRef<[u8]> trait for slice access

57

impl AsRef<[u8]> for Buffer;

58

59

impl From<&str> for Buffer;

60

impl From<String> for Buffer;

61

impl From<Vec<u8>> for Buffer;

62

impl From<Bytes> for Buffer;

63

impl From<&[u8]> for Buffer;

64

```

65

66

**Usage Examples:**

67

68

```rust

69

use opendal::Buffer;

70

71

// Create buffer from various sources

72

let buf1 = Buffer::from("Hello, World!");

73

let buf2 = Buffer::from(vec![1, 2, 3, 4, 5]);

74

let buf3 = Buffer::from_static(b"static data");

75

76

// Write buffer to storage

77

op.write("text.txt", buf1).await?;

78

op.write("binary.dat", buf2).await?;

79

80

// Buffer operations

81

let data = op.read("file.txt").await?;

82

println!("Size: {} bytes", data.len());

83

let text = String::from_utf8_lossy(data.as_ref());

84

```

85

86

### Directory Entry Types

87

88

Types for directory listing and file system navigation.

89

90

```rust { .api }

91

/// Directory entry containing path and metadata

92

pub struct Entry {

93

path: String,

94

metadata: Metadata,

95

}

96

97

impl Entry {

98

/// Get entry path

99

pub fn path(&self) -> &str;

100

101

/// Get entry metadata

102

pub fn metadata(&self) -> &Metadata;

103

104

/// Get entry mode (file/directory)

105

pub fn mode(&self) -> EntryMode;

106

107

/// Get entry name (basename)

108

pub fn name(&self) -> &str;

109

110

/// Consume entry and return its parts

111

pub fn into_parts(self) -> (String, Metadata);

112

}

113

114

/// File system entry type

115

#[derive(Debug, Clone, Copy, PartialEq, Eq)]

116

pub enum EntryMode {

117

/// Regular file

118

FILE,

119

/// Directory

120

DIR,

121

/// Unknown type

122

Unknown,

123

}

124

125

impl EntryMode {

126

/// Check if entry is a file

127

pub fn is_file(&self) -> bool;

128

129

/// Check if entry is a directory

130

pub fn is_dir(&self) -> bool;

131

}

132

```

133

134

**Usage Examples:**

135

136

```rust

137

use opendal::{EntryMode, Entry};

138

139

// List directory entries

140

let entries = op.list("/documents/").await?;

141

142

for entry in entries {

143

match entry.mode() {

144

EntryMode::FILE => {

145

println!("File: {} ({} bytes)",

146

entry.path(),

147

entry.metadata().content_length()

148

);

149

},

150

EntryMode::DIR => {

151

println!("Directory: {}", entry.path());

152

},

153

EntryMode::Unknown => {

154

println!("Unknown: {}", entry.path());

155

}

156

}

157

}

158

```

159

160

### Metadata Types

161

162

Comprehensive metadata system for file attributes and properties.

163

164

```rust { .api }

165

/// File metadata containing size, timestamps, and other attributes

166

pub struct Metadata {

167

bit: BitSet<Metakey>,

168

mode: EntryMode,

169

cache_control: Option<String>,

170

content_disposition: Option<String>,

171

content_length: Option<u64>,

172

content_md5: Option<String>,

173

content_range: Option<BytesContentRange>,

174

content_type: Option<String>,

175

etag: Option<String>,

176

last_modified: Option<OffsetDateTime>,

177

version: Option<String>,

178

}

179

180

impl Metadata {

181

/// Get entry mode (file/directory/unknown)

182

pub fn mode(&self) -> EntryMode;

183

184

/// Get content length in bytes

185

pub fn content_length(&self) -> u64;

186

187

/// Get content MIME type

188

pub fn content_type(&self) -> Option<&str>;

189

190

/// Get content MD5 hash

191

pub fn content_md5(&self) -> Option<&str>;

192

193

/// Get content range information

194

pub fn content_range(&self) -> Option<BytesContentRange>;

195

196

/// Get ETag for caching/versioning

197

pub fn etag(&self) -> Option<&str>;

198

199

/// Get last modified timestamp

200

pub fn last_modified(&self) -> Option<OffsetDateTime>;

201

202

/// Get object version

203

pub fn version(&self) -> Option<&str>;

204

205

/// Get cache control header

206

pub fn cache_control(&self) -> Option<&str>;

207

208

/// Get content disposition header

209

pub fn content_disposition(&self) -> Option<&str>;

210

211

/// Check if specific metadata is available

212

pub fn contains_metakey(&self, key: Metakey) -> bool;

213

}

214

215

/// Metadata keys for selective fetching

216

#[derive(Debug, Clone, Copy)]

217

pub enum Metakey {

218

/// Complete metadata (all fields)

219

Complete,

220

/// Entry mode only

221

Mode,

222

/// Cache control header

223

CacheControl,

224

/// Content length

225

ContentLength,

226

/// Content MD5 hash

227

ContentMd5,

228

/// Content MIME type

229

ContentType,

230

/// Content range

231

ContentRange,

232

/// ETag for versioning

233

Etag,

234

/// Last modified timestamp

235

LastModified,

236

/// Object version

237

Version,

238

/// Content disposition

239

ContentDisposition,

240

}

241

242

impl Metakey {

243

/// Convert from string representation

244

pub fn from_str(s: &str) -> Option<Self>;

245

246

/// Get string representation

247

pub fn as_str(&self) -> &'static str;

248

}

249

```

250

251

**Usage Examples:**

252

253

```rust

254

use opendal::{Metadata, Metakey};

255

use time::OffsetDateTime;

256

257

// Get complete metadata

258

let metadata = op.stat("document.pdf").await?;

259

260

// Access metadata fields

261

println!("Size: {} bytes", metadata.content_length());

262

println!("Type: {:?}", metadata.content_type());

263

println!("ETag: {:?}", metadata.etag());

264

265

if let Some(modified) = metadata.last_modified() {

266

println!("Last modified: {}", modified);

267

}

268

269

// Selective metadata fetching

270

let partial_meta = op.stat_with("large-file.zip")

271

.metakey(Metakey::ContentLength | Metakey::LastModified)

272

.await?;

273

274

// Check what metadata is available

275

if partial_meta.contains_metakey(Metakey::ContentLength) {

276

println!("Size is available: {}", partial_meta.content_length());

277

}

278

```

279

280

### Service and Capability Types

281

282

Types for service identification and capability detection.

283

284

```rust { .api }

285

/// Storage service scheme identifier

286

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

287

pub enum Scheme {

288

// Major cloud providers

289

S3, Gcs, Azblob, Oss, Obs, Cos,

290

// File systems

291

Fs, Hdfs, HdfsNative, Webdav, Ftp, Sftp,

292

// Databases

293

Redis, Postgresql, Mysql, Sqlite, Mongodb, Rocksdb,

294

// Memory/Cache

295

Memory, Dashmap, Memcached, Moka, MiniMoka, Cacache,

296

// Platform services

297

Github, Dropbox, Onedrive, Gdrive, Supabase,

298

// Specialized

299

Http, Ipfs, Alluxio,

300

// ... and 30+ more services

301

}

302

303

impl Scheme {

304

/// Parse scheme from string

305

pub fn from_str(s: &str) -> Result<Self>;

306

307

/// Get string representation

308

pub fn into_static(self) -> &'static str;

309

}

310

311

/// Service capability description

312

pub struct Capability {

313

stat: bool,

314

stat_with_if_match: bool,

315

stat_with_if_none_match: bool,

316

read: bool,

317

read_with_range: bool,

318

read_with_if_match: bool,

319

read_with_if_none_match: bool,

320

write: bool,

321

write_can_multi: bool,

322

write_can_empty: bool,

323

write_can_append: bool,

324

write_with_cache_control: bool,

325

write_with_content_type: bool,

326

write_with_content_disposition: bool,

327

create_dir: bool,

328

delete: bool,

329

copy: bool,

330

rename: bool,

331

list: bool,

332

list_with_limit: bool,

333

list_with_start_after: bool,

334

list_with_recursive: bool,

335

presign: bool,

336

presign_read: bool,

337

presign_stat: bool,

338

presign_write: bool,

339

batch: bool,

340

batch_delete: bool,

341

batch_max_operations: Option<usize>,

342

blocking: bool,

343

}

344

345

impl Capability {

346

/// Check if operation is supported

347

pub fn stat(&self) -> bool;

348

pub fn read(&self) -> bool;

349

pub fn write(&self) -> bool;

350

pub fn delete(&self) -> bool;

351

pub fn list(&self) -> bool;

352

pub fn copy(&self) -> bool;

353

pub fn rename(&self) -> bool;

354

pub fn create_dir(&self) -> bool;

355

pub fn presign(&self) -> bool;

356

pub fn batch(&self) -> bool;

357

pub fn blocking(&self) -> bool;

358

359

/// Check option support

360

pub fn read_with_range(&self) -> bool;

361

pub fn write_with_content_type(&self) -> bool;

362

pub fn list_with_recursive(&self) -> bool;

363

364

/// Get batch operation limits

365

pub fn batch_max_operations(&self) -> Option<usize>;

366

}

367

368

/// Operator information

369

pub struct OperatorInfo {

370

scheme: Scheme,

371

root: String,

372

name: String,

373

capability: Capability,

374

}

375

376

impl OperatorInfo {

377

/// Get service scheme

378

pub fn scheme(&self) -> Scheme;

379

380

/// Get root path

381

pub fn root(&self) -> &str;

382

383

/// Get service name

384

pub fn name(&self) -> &str;

385

386

/// Get service capabilities

387

pub fn full_capability(&self) -> &Capability;

388

}

389

```

390

391

**Usage Examples:**

392

393

```rust

394

use opendal::{Scheme, Capability};

395

396

// Get operator information

397

let info = op.info();

398

println!("Service: {:?}", info.scheme());

399

println!("Root: {}", info.root());

400

401

// Check capabilities

402

let cap = info.full_capability();

403

if cap.presign() {

404

let presigned = op.presign_read("file.txt", Duration::from_secs(3600)).await?;

405

println!("Presigned URL: {}", presigned.uri());

406

} else {

407

println!("Presigned URLs not supported");

408

}

409

410

// Conditional operations based on capabilities

411

if cap.batch() {

412

// Use batch operations

413

op.remove(vec!["file1.txt".to_string(), "file2.txt".to_string()]).await?;

414

} else {

415

// Fall back to individual operations

416

op.delete("file1.txt").await?;

417

op.delete("file2.txt").await?;

418

}

419

```

420

421

### Error Handling Types

422

423

Comprehensive error system with detailed context and error classification.

424

425

```rust { .api }

426

/// Main error type with rich context

427

pub struct Error {

428

kind: ErrorKind,

429

message: Cow<'static, str>,

430

source: Option<anyhow::Error>,

431

operation: Operation,

432

path: String,

433

context: HashMap<&'static str, String>,

434

}

435

436

impl Error {

437

/// Get error kind

438

pub fn kind(&self) -> ErrorKind;

439

440

/// Get error message

441

pub fn to_string(&self) -> String;

442

443

/// Get operation that failed

444

pub fn operation(&self) -> Operation;

445

446

/// Get path involved in error

447

pub fn path(&self) -> &str;

448

449

/// Get additional context

450

pub fn context(&self) -> &HashMap<&'static str, String>;

451

}

452

453

/// Error classification

454

#[derive(Debug, Clone, Copy, PartialEq, Eq)]

455

pub enum ErrorKind {

456

/// Configuration is invalid

457

ConfigInvalid,

458

/// Path or resource not found

459

NotFound,

460

/// Permission denied

461

PermissionDenied,

462

/// Resource is a directory when file expected

463

IsADirectory,

464

/// Resource is not a directory when directory expected

465

NotADirectory,

466

/// Resource already exists

467

AlreadyExists,

468

/// Rate limited by service

469

RateLimited,

470

/// Service is busy, try again later

471

IsBusy,

472

/// Request does not contain valid range

473

RangeNotSatisfied,

474

/// Condition failed (e.g., if-match)

475

ConditionNotMatch,

476

/// Content is incomplete

477

ContentIncomplete,

478

/// Content length mismatch

479

ContentTruncated,

480

/// Operation not supported by service

481

Unsupported,

482

/// Unexpected error (catch-all)

483

Unexpected,

484

}

485

486

impl ErrorKind {

487

/// Check if error is retryable

488

pub fn is_retryable(&self) -> bool;

489

490

/// Check if error is temporary

491

pub fn is_temporary(&self) -> bool;

492

}

493

494

/// Operation type for error context

495

#[derive(Debug, Clone, Copy)]

496

pub enum Operation {

497

Read,

498

Write,

499

Stat,

500

Delete,

501

List,

502

Copy,

503

Rename,

504

CreateDir,

505

Presign,

506

Batch,

507

}

508

509

/// Standard Result type

510

pub type Result<T> = std::result::Result<T, Error>;

511

```

512

513

**Usage Examples:**

514

515

```rust

516

use opendal::{Error, ErrorKind, Result};

517

518

// Pattern matching on error kinds

519

match op.read("missing-file.txt").await {

520

Ok(data) => println!("Success: {} bytes", data.len()),

521

Err(e) => {

522

match e.kind() {

523

ErrorKind::NotFound => {

524

println!("File not found: {}", e.path());

525

},

526

ErrorKind::PermissionDenied => {

527

println!("Access denied: {}", e.path());

528

},

529

ErrorKind::RateLimited => {

530

println!("Rate limited, retrying later...");

531

// Implement backoff logic

532

},

533

kind if kind.is_retryable() => {

534

println!("Retryable error: {}", e);

535

// Retry logic

536

},

537

_ => {

538

eprintln!("Unexpected error: {}", e);

539

return Err(e);

540

}

541

}

542

}

543

}

544

545

// Error context inspection

546

if let Err(e) = op.write("readonly/file.txt", "data").await {

547

println!("Operation: {:?}", e.operation());

548

println!("Path: {}", e.path());

549

println!("Kind: {:?}", e.kind());

550

551

// Access additional context

552

for (key, value) in e.context() {

553

println!("Context {}: {}", key, value);

554

}

555

}

556

557

// Converting to std::io::Error for compatibility

558

let io_error: std::io::Error = opendal_error.into();

559

```

560

561

### Range and Utility Types

562

563

Supporting types for operations and configurations.

564

565

```rust { .api }

566

use std::ops::{Range, RangeFrom, RangeTo, RangeInclusive, RangeFull, RangeBounds};

567

568

// OpenDAL uses standard Rust range types for byte range operations.

569

// Any type implementing RangeBounds<u64> can be used for range operations:

570

571

// Examples of supported range types:

572

// - Range<u64>: 0..1024 (bytes 0 to 1023)

573

// - RangeFrom<u64>: 1024.. (from byte 1024 to end)

574

// - RangeTo<u64>: ..1024 (from start to byte 1023)

575

// - RangeInclusive<u64>: 0..=1023 (bytes 0 to 1023 inclusive)

576

// - RangeFull: .. (full range, all bytes)

577

578

/// Presigned request details

579

pub struct PresignedRequest {

580

method: http::Method,

581

uri: http::Uri,

582

headers: http::HeaderMap,

583

}

584

585

impl PresignedRequest {

586

/// Get HTTP method

587

pub fn method(&self) -> &http::Method;

588

589

/// Get request URI

590

pub fn uri(&self) -> &http::Uri;

591

592

/// Get HTTP headers

593

pub fn headers(&self) -> &http::HeaderMap;

594

}

595

```

596

597

**Usage Examples:**

598

599

```rust

600

use std::ops::{Range, RangeFrom, RangeTo};

601

602

// OpenDAL accepts standard Rust range types directly

603

let partial_data = op.read_with("large-file.dat")

604

.range(0..8192) // Read first 8KB (Range<u64>)

605

.await?;

606

607

// Different range types supported

608

let from_middle = op.read_with("data.bin")

609

.range(1024..) // From byte 1024 to end (RangeFrom<u64>)

610

.await?;

611

612

let first_kb = op.read_with("file.txt")

613

.range(..1024) // First 1024 bytes (RangeTo<u64>)

614

.await?;

615

616

let inclusive_range = op.read_with("doc.pdf")

617

.range(0..=1023) // First 1024 bytes inclusive (RangeInclusive<u64>)

618

.await?;

619

620

// Content range information is available in metadata for partial responses

621

let metadata = op.stat("file.txt").await?;

622

if let Some(_content_range) = metadata.content_range() {

623

// Content range details are available but typically not needed by users

624

println!("Partial content response received");

625

}

626

```