package moe.nea.pcj.json; import moe.nea.pcj.Codec; import moe.nea.pcj.Result; import java.util.ArrayList; import java.util.List; public interface JsonCodec extends Codec< T, Format, JsonLikeOperations, JsonLikeError, JsonLikeError> { default JsonCodec, Format> listOf() { return new JsonCodec<>() { @Override public Result encode(List data, JsonLikeOperations ops) { var list = ops.createList(); var erros = new ArrayList(); for (int i = 0; i < data.size(); i++) { var datum = data.get(i); final var index = i; var result = JsonCodec.this.encode(datum, ops) .mapError(it -> new AtIndex(index, it)); erros.addAll(result.errors()); result.valueOrPartial().ifPresent(list::add); } return Result.ok(list.complete()).appendErrors(erros); } @Override public Result, JsonLikeError> decode(Format format, JsonLikeOperations ops) { var view = Result., JsonLikeError>cast(ops.getList(format)); return view.flatMap(elements -> { var acc = new ArrayList(elements.length()); var errors = new ArrayList(); for (int i = 0; i < elements.length(); i++) { final var index = i; var result = JsonCodec.this.decode(elements.getUnsafe(i), ops) .mapError(it -> new AtIndex(index, it)); errors.addAll(result.errors()); result.valueOrPartial().ifPresent(acc::add); } return Result., JsonLikeError>ok(acc).appendErrors(errors); }); } }; } default JsonCodec named(String name) { return new JsonCodec<>() { @Override public Result decode(Format format, JsonLikeOperations ops) { return JsonCodec.this.decode(format, ops).mapError(it -> new NamedObject(name, it)); } @Override public Result encode(T data, JsonLikeOperations ops) { return JsonCodec.this.encode(data, ops).mapError(it -> new NamedObject(name, it)); } }; } default MapCodec fieldOf(String key) { return new MapCodec<>() { @Override public Result decode(RecordView record, JsonLikeOperations ops) { return record.get(key) .map(element -> Result.cast( JsonCodec.this.decode(element, ops) .mapError(it -> new AtField(key, it)))) .orElseGet(() -> Result.fail(new MissingKey(key))); } @Override public Result, JsonLikeError> encode(T value, JsonLikeOperations ops) { var record = ops.createObject(); return Result.cast(JsonCodec.this.encode(value, ops)) .mapError(it -> new AtField(key, it)) .flatMap(json -> Result.cast(record.add(key, json).map(unit -> record))); } }; } }