API 읽는 법: 오류와 소유권
인자의 단위, 결과 구조체, 부분 성공과 자원 수명을 이해합니다.
Wave Foundation
선언 읽기
다음은 함수 선언을 설명하는 표기이며 실행 가능한 파일 전체가 아닙니다.
io_read(fd: i64, buf: ptr<u8>, len: i64) -> i64
fd는 열린 디스크립터, buf는 호출자가 제공한 저장 공간, len은 쓸 수 있는 바이트 수입니다. i64라고 해서 음수 길이가 유효한 것은 아닙니다. 반환값은 요청 길이가 아니라 실제 읽은 바이트 수이므로, 반환된 범위만 사용합니다.
실패 표현은 함수마다 다름
| 방식 | 예 | 검사 방법 |
|---|---|---|
| 포인터 또는 null | mem_alloc |
null 검사 뒤 메모리 접근 |
| 바이트 수 또는 음수 | io_read |
음수 오류, 0 EOF, 양수 데이터 |
| 상태 코드 | buffer_push |
BUFFER_OK와 오류 상수 비교 |
| 성공 여부와 값 | NetResult<T> |
ok를 검사한 뒤 value 사용 |
| 부분 진행량 포함 | RandomFillResult |
ok, written, error를 함께 확인 |
오류의 숫자만 보고 다른 모듈의 상수와 비교하지 않습니다. 예를 들어 env의 오류 번호와 OS errno는 같은 체계가 아닙니다. WASI의 원본 오류를 Linux errno처럼 해석해서도 안 됩니다.
소유와 빌림
- 소유: 할당 메모리, 열린 파일, 열린 소켓을 얻으면 대응하는 해제·닫기를 호출할 책임이 있습니다.
- 빌림: 바이트 view나 함수에 전달한 버퍼는 기존 메모리를 참조합니다. 함수가 소유권을 받는다고 명시하지 않으면 호출자가 계속 관리합니다.
- 출력 인자:
out_value: ptr<T>처럼 받는 함수에는 결과를 쓸 수 있는 유효한 저장 공간을 전달합니다. 성공한 경우에만 결과가 유효하다는 계약인지 확인합니다.
Buffer를 구조체 값으로 복사하면 같은 할당을 가리킬 수 있습니다. 복사본마다 해제하지 않습니다. 빌린 포인터는 원본 해제나 재할당 이후 사용할 수 없습니다. 문자열 리터럴은 변경 가능한 버퍼로 취급하지 않습니다.
실패가 이전 상태로 되돌린다는 뜻은 아님
io_write_all은 일부 바이트를 쓴 뒤 실패할 수 있습니다. 이미 외부에 쓴 바이트는 되돌아가지 않습니다. 반면 bytes의 checked cursor 읽기는 실패하면 위치와 출력값을 보존합니다. 이런 차이는 API별로 명시합니다.