# memory_region.region

> A module of memory-region's API.

Where a region's bytes come from, and what giving them back means.

A region is a contiguous byte range. What differs between one and the next is
how it was obtained — an allocation, a mapped file, later perhaps a slab in an
object store or a pinned buffer on the way to a GPU — and what releasing it
means. Nothing that carves a region up needs to know which it has.

## Dropping one is safe; giving it away is explicit

A region frees or unmaps itself when it goes out of scope, because the failure
it would otherwise have is invisible: a leaked mapping produces no error, no
crash and nothing in the output, and the file stays open through it.

`into_raw` is the way out for the case that is not a leak — an export whose
bytes become the consumer's, freed later by its own release callback. It
consumes the region, so the destructor does not also run, and the transfer is
readable at the call site instead of being implied by an omission.

Mojo can do better than this: `@explicit_destroy` with a `not Deinitable`
conformance makes abandoning a region a *compile* error naming the method to
call. It is not used here because it needs a September-2026 nightly, and these
tins build on `mojo-compiler` 1.2.0. Worth revisiting when stable catches up —
it turns a safe default into an impossible mistake.

## Structs

### `HeapRegion`

```mojo
struct HeapRegion
```

An ordinary allocation: what an in-process export has always used.

Implements: `Movable`, `Region`

#### `__init__`

```mojo
def __init__(out self, size: Int)
```

#### `__deinit__`

```mojo
def __deinit__(deinit self)
```

Freed when it goes out of scope, unless `into_raw` took it.

#### `base`

```mojo
def base(self) -> Int
```

#### `size`

```mojo
def size(self) -> Int
```

#### `close`

```mojo
def close(deinit self)
```

Hand the allocation back, now rather than at the end of scope.

#### `into_raw`

```mojo
def into_raw(deinit self) -> Int
```

Give up ownership; returns the base address.

For a consumer that will free the bytes itself — the Arrow C Data
Interface being the case this exists for, where the release callback
on the exported array is what eventually frees the block.

### `MappedRegion`

```mojo
struct MappedRegion
```

A file mapped `MAP_SHARED`, which a peer process can map by name.

The file is the handle. A consumer needs the path and nothing else:
everything inside is laid out by offset, so it can map the same bytes
wherever its own address space happens to put them.

Implements: `Movable`, `Region`

Fields:

- `path: String`: Where a peer will find these bytes.

#### `__init__`

```mojo
def __init__(out self, var path: String, size: Int)
```

Create (or truncate) `path` at `size` bytes and map it writable.

#### `__deinit__`

```mojo
def __deinit__(deinit self)
```

Unmapped when it goes out of scope, unless `into_raw` took it.

#### `base`

```mojo
def base(self) -> Int
```

#### `size`

```mojo
def size(self) -> Int
```

#### `close`

```mojo
def close(deinit self)
```

Drop this process's view of the bytes. The file stays.

Unlinking is deliberately not done here: the consumer may not have
mapped it yet, and when the bytes stop being needed is the caller's
business rather than the region's.

#### `into_raw`

```mojo
def into_raw(deinit self) -> Int
```

Leave the mapping in place and give up ownership of it.

### `SharedMapping`

```mojo
struct SharedMapping
```

The consumer's half: a peer's region, mapped read-only by path.

It lands wherever this address space puts it, and everything inside is
reached by offset from there. Unmapped at end of scope, like a region.

Views come out of `span` and `bytes`, and carry this mapping's origin.
That makes two mistakes compile errors rather than crashes: writing
through a view (the pages are `PROT_READ`, so a write would fault), and
holding a view after the mapping has gone (it would point at nothing).

What the types cannot promise is anything about the bytes: offsets come
from another process's manifest, so `span` checks them against the
mapping at run time, and the producer can still rewrite or truncate the
file underneath a view.

It is deliberately not a `Region`: a region is something a
`BumpAllocator` carves up and writes into, and this one cannot be written.

Implements: `Movable`

Fields:

- `path: String`: The file these bytes were mapped from.

#### `__init__`

```mojo
def __init__(out self, var path: String)
```

Map `path` read-only, all of it.

#### `__deinit__`

```mojo
def __deinit__(deinit self)
```

Unmapped when it goes out of scope.

#### `size`

```mojo
def size(self) -> Int
```

How many bytes are mapped: the file's length when it was opened.

#### `span`

```mojo
def span[dtype: DType](self, offset: Int, count: Int) -> Span[Scalar[dtype], origin_of(self)]
```

`count` values of `dtype` starting `offset` bytes in, read-only.

Raises if they do not fit inside the mapping, or if `offset` is not
aligned for `dtype` — both things a manifest from another process can
get wrong, and neither of which a type can rule out.

#### `bytes`

```mojo
def bytes(self) -> Span[UInt8, origin_of(self)]
```

The whole mapping, as bytes.

#### `unsafe_base`

```mojo
def unsafe_base(self) -> Int
```

Address of byte 0 in this process, untracked.

For handing a buffer to something outside Mojo's view — an Arrow
C Data import, a foreign function. The address is only good while
this mapping is alive, and nothing checks that.

## Traits

### `Region`

```mojo
undefined
```

A contiguous byte range that something else owns the lifetime of.

Implements: `Movable`

#### `base`

```mojo
def base(self) -> Int
```

Address of byte 0 **in this process**.

#### `size`

```mojo
def size(self) -> Int
```

How many bytes it holds.

#### `close`

```mojo
def close(deinit self)
```

Give the bytes back: free, unmap, whatever this region means.

#### `into_raw`

```mojo
def into_raw(deinit self) -> Int
```

Give up ownership; returns the base address.

For bytes that become someone else's — an Arrow export whose release
callback frees them later. Consuming, so the destructor does not also
run.

## Functions

### `map_shared`

```mojo
def map_shared(path: String) -> Tuple[Int, Int]
```

Map an existing file read-only; returns `(address, length)`.

Nothing ever unmaps what this returns. Kept for one release while callers
move to `SharedMapping`.

Deprecated: use SharedMapping(path): it unmaps itself and checks offsets
