Add fmt.User_Formatter

This commit is contained in:
gingerBill
2020-06-08 12:40:50 +01:00
parent a7dd686859
commit 0ffb718a91

View File

@@ -10,7 +10,6 @@ import "core:strings"
import "core:reflect"
import "intrinsics"
@private
DEFAULT_BUFFER_SIZE :: 1<<12;
@@ -35,6 +34,34 @@ Info :: struct {
record_level: int,
}
// Custom formatter signature. It returns true if the formatting was successful and false when it could not be done
User_Formatter :: #type proc(fi: ^Info, arg: any, verb: rune) -> bool;
Register_User_Formatter_Error :: enum {
None,
No_User_Formatter,
Formatter_Previously_Found,
}
// NOTE(bill): This is a pointer to prevent accidental additions
// it is prefixed with `_` rather than marked with a private attribute so that users can access it if necessary
_user_formatters: ^map[typeid]User_Formatter;
set_user_formatters :: proc(m: ^map[typeid]User_Formatter) {
_user_formatters = m;
}
register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Register_User_Formatter_Error {
if _user_formatters == nil {
return .No_User_Formatter;
}
if prev, found := _user_formatters[id]; found && prev != nil {
return .Formatter_Previously_Found;
}
_user_formatters[id] = formatter;
return .None;
}
fprint :: proc(fd: os.Handle, args: ..any) -> int {
data: [DEFAULT_BUFFER_SIZE]byte;
buf := strings.builder_from_slice(data[:]);
@@ -1189,6 +1216,16 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
return;
}
if _user_formatters != nil {
formatter := _user_formatters[v.id];
if formatter != nil {
if ok := formatter(fi, v, verb); !ok {
fmt_bad_verb(fi, verb);
}
return;
}
}
type_info := type_info_of(v.id);
switch info in type_info.variant {
case runtime.Type_Info_Any: // Ignore
@@ -1795,6 +1832,16 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
return;
}
if _user_formatters != nil {
formatter := _user_formatters[arg.id];
if formatter != nil {
if ok := formatter(fi, arg, verb); !ok {
fmt_bad_verb(fi, verb);
}
return;
}
}
custom_types: switch a in arg {
case runtime.Source_Code_Location: