//! Memory mapping abstraction
#ifndef _MAP_H
#define _MAP_H

#include <stdbool.h>
#include "ints.h"

typedef enum mm_err {
	MAP_ERR_UNKNOWN = 0,
	MAP_SUCCESS = 1,

	MAP_ERR_MMAP,
	MAP_ERR_UNMAP,
	MAP_ERR_OPEN,
	MAP_ERR_CLOSE,
	MAP_ERR_STAT,
	MAP_ERR_ADVISE,
} map_result_t;

typedef union memory_map {
	// Common
	struct {
		union {
			void* origin;
			u8* area;
		};
		usize len;
	};
	// Specific to anon / file
	struct mm_file {	
		void* origin;
		usize len;

		off_t fd_offset;
		int fd;
	} file;
	struct mm_anon {
		void* origin;
		usize len;
	} anon;

} map_t;

map_result_t map_fd(int fd, bool write, usize size, off_t offset, map_t *pOUT map);
/// Specify size as 0 to use the file's full size for the map.
map_result_t map_file(const char* file, bool write, usize size, off_t offset, map_t *pOUT map);
map_result_t map_anon(void* ptr, usize len, map_t *pOUT map);
map_result_t map_free(map_t map);
map_result_t map_preload(map_t *pINOUT map, bool random);

const char* map_error_str(map_result_t res);

_mixin int _map_handle_err(const char* stmt, const char* file, int line, const char* func, map_result_t res)
{
	if(res == MAP_SUCCESS) return 1;
	else {
		const char* err = map_error_str(res);
		ERROR("mapping failed at %s:%d->%s(): on stmt `%s`", file, line, func, stmt);
		switch(res) {
			// Non-errno errors
			case MAP_ERR_UNKNOWN:
			case MAP_SUCCESS:
				fprintf(stderr, err);
				if(0)
			// errno errors
			default:
				perror(err);
				return 0;
		}
	}
}
#define map_handle_err(stmt) _map_handle_err(#stmt, __FILE__, __LINE__, __func__, stmt)

#endif /* _MAP_H */
