Removed unused feature.

Optimized use statements in main.

Simplified truth_combinations code a little.

Updated OpenAPI spec
This commit is contained in:
Martin Berg Alstad 2024-06-22 20:38:55 +02:00
parent 38fc8ce383
commit 1b94e63915
11 changed files with 566 additions and 86 deletions

1
Cargo.lock generated
View File

@ -675,7 +675,6 @@ dependencies = [
"http-body",
"http-body-util",
"pin-project-lite",
"tower",
"tower-layer",
"tower-service",
"tracing",

View File

@ -13,7 +13,7 @@ tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] }
serde = { version = "1.0.203", features = ["derive", "rc"] }
# API
axum = { version = "0.7.5", features = ["macros"] }
tower-http = { version = "0.5.2", features = ["cors", "trace", "normalize-path", "tower"] }
tower-http = { version = "0.5.2", features = ["cors", "trace", "normalize-path"] }
tower = "0.4.13"
# Logging
tracing = "0.1.40"

View File

@ -1,12 +1,71 @@
openapi: 3.0.0
info:
title: Simplify Truth Expressions
title: Simplify Truth API
description: A service to simplify truth expressions, and generate truth tables.
version: v2
tags: []
tags:
- name: Common
- name: Expression
- name: Table
paths:
/simplify/{exp}:
/:
get:
operationId: Simplify_simplify
tags:
- Common
operationId: Index_index
summary: Information
description: Information about this API.
parameters: []
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/Responses.InfoResponse'
/is-valid/{exp}:
get:
tags:
- Common
- Expression
operationId: Index_isValid
summary: Check if an expression is valid
description: Check if an expression is valid.
parameters:
- name: exp
in: path
required: true
schema:
type: string
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/Responses.IsValidResponse'
/openapi:
get:
tags:
- Common
operationId: Index_openAPI
summary: The OpenAPI specification
description: The OpenAPI specification for this API.
parameters: []
responses:
'200':
description: Returns a response as HTML, with the content type set to "text/html".
content:
text/html:
schema:
type: string
/simplify/table/{exp}:
get:
tags:
- Expression
- Table
operationId: Simplify_simplifyTable
summary: Simplify and generate a truth table
parameters:
- name: exp
in: path
@ -17,14 +76,62 @@ paths:
in: query
required: false
schema:
$ref: '#/components/schemas/SimplifyOptions'
$ref: '#/components/schemas/Options.SimplifyTableOptions'
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/SimplifyResponse'
$ref: '#/components/schemas/Responses.SimplifyTableResponse'
/simplify/{exp}:
get:
tags:
- Expression
operationId: Simplify_simplify
summary: Simplify a truth expression
parameters:
- name: exp
in: path
required: true
schema:
type: string
- name: query
in: query
required: false
schema:
$ref: '#/components/schemas/Options.SimplifyOptions'
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/Responses.SimplifyResponse'
/table/{exp}:
get:
tags:
- Table
operationId: TruthTable_simplify
summary: Generate a truth table
parameters:
- name: exp
in: path
required: true
schema:
type: string
- name: query
in: query
required: false
schema:
$ref: '#/components/schemas/Options.TableOptions'
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/Responses.TruthTableResponse'
components:
schemas:
Expression:
@ -32,12 +139,14 @@ components:
- $ref: '#/components/schemas/Models.ExpressionNot'
- $ref: '#/components/schemas/Models.ExpressionBinary'
- $ref: '#/components/schemas/Models.ExpressionAtomic'
title: A truth expression
Models.BinaryOperator:
type: string
enum:
- AND
- OR
- IMPLICATION
title: A binary operator
Models.ExpressionAtomic:
type: object
required:
@ -45,6 +154,8 @@ components:
properties:
atomic:
type: string
title: The atomic value
title: An atomic expression
Models.ExpressionBinary:
type: object
required:
@ -53,52 +164,214 @@ components:
- right
properties:
left:
$ref: '#/components/schemas/Expression'
allOf:
- $ref: '#/components/schemas/Expression'
title: The left expression
operator:
$ref: '#/components/schemas/Models.BinaryOperator'
allOf:
- $ref: '#/components/schemas/Models.BinaryOperator'
title: The binary operator
right:
$ref: '#/components/schemas/Expression'
allOf:
- $ref: '#/components/schemas/Expression'
title: The right expression
title: A binary expression
Models.ExpressionNot:
type: object
required:
- not
properties:
not:
$ref: '#/components/schemas/Expression'
SimplifyOptions:
allOf:
- $ref: '#/components/schemas/Expression'
title: The expression to negate
title: The inverse of an expression
Models.TruthTable:
type: object
required:
- lang
- simplify
- caseSensitive
- header
- truthMatrix
properties:
header:
type: array
items:
type: string
title: The header of the truth table
truthMatrix:
type: array
items:
type: array
items:
type: boolean
title: The rows and columns of the truth table
title: A truth table
Options.Hide:
type: string
enum:
- NONE
- 'TRUE'
- 'FALSE'
title: Whether to hide specific rows in a truth table
Options.SimplifyOptions:
type: object
properties:
lang:
type: string
enum:
- en
- nb
default: en
simplify:
type: boolean
title: Whether to simplify the expression
default: true
caseSensitive:
ignoreCase:
type: boolean
title: Whether to ignore case when simplifying
default: false
SimplifyResponse:
title: Options for simplifying an expression
Options.SimplifyTableOptions:
type: object
properties:
simplify:
type: boolean
title: Whether to simplify the expression
default: true
ignoreCase:
type: boolean
title: Whether to ignore case when simplifying
default: false
sort:
allOf:
- $ref: '#/components/schemas/Options.Sort'
title: Sort order for the truth table
default: DEFAULT
hide:
allOf:
- $ref: '#/components/schemas/Options.Hide'
title: Hide specific rows in the truth table
default: NONE
hideIntermediateSteps:
type: boolean
description: |-
Hide intermediate steps when generating the truth table
For example in the expression "A and B or C", the intermediate step is: A and B
title: Hide intermediate steps when generating the truth table
default: false
title: Options for simplifying an expression and generating a truth table
Options.Sort:
type: string
enum:
- DEFAULT
- TRUE_FIRST
- FALSE_FIRST
title: Sort order for a truth table
Options.TableOptions:
type: object
properties:
sort:
allOf:
- $ref: '#/components/schemas/Options.Sort'
title: Sort order for the truth table
default: DEFAULT
hide:
allOf:
- $ref: '#/components/schemas/Options.Hide'
title: Hide specific rows in the truth table
default: NONE
hideIntermediateSteps:
type: boolean
description: |-
Hide intermediate steps when generating the truth table
For example in the expression "A and B or C", the intermediate step is: A and B
title: Hide intermediate steps when generating the truth table
default: false
title: Options for generating a truth table
Responses.InfoResponse:
type: object
required:
- message
- docs
- createdBy
properties:
message:
type: string
docs:
type: string
createdBy:
type: string
description: Information about this API.
title: Information
Responses.IsValidResponse:
type: object
required:
- isValid
properties:
isValid:
type: boolean
description: If an expression is valid.
title: If an expression is valid
Responses.SimplifyResponse:
type: object
required:
- before
- after
- operations
- expression
properties:
before:
type: string
title: Before simplification
after:
type: string
orderOfOperations:
title: After simplification
operations:
type: array
items:
type: string
default: []
title: Steps taken to simplify
expression:
$ref: '#/components/schemas/Expression'
allOf:
- $ref: '#/components/schemas/Expression'
title: The simplified expression
description: Response after simplifying an expression.
title: Simplify Response
Responses.SimplifyTableResponse:
type: object
required:
- before
- after
- operations
- expression
- truthTable
properties:
before:
type: string
title: Before simplification
after:
type: string
title: After simplification
operations:
type: array
items:
type: string
title: Steps taken to simplify
expression:
allOf:
- $ref: '#/components/schemas/Expression'
title: The simplified expression
truthTable:
allOf:
- $ref: '#/components/schemas/Models.TruthTable'
title: The truth table
description: Response after simplifying an expression and generating a truth table.
title: Simplify and Table Response
Responses.TruthTableResponse:
type: object
required:
- truthTable
properties:
truthTable:
allOf:
- $ref: '#/components/schemas/Models.TruthTable'
title: The truth table
description: Response after generating a truth table.
title: Truth Table Response
Version:
type: string
enum:
- v2

View File

@ -1,38 +1,75 @@
import "@typespec/http";
import "@typespec/versioning";
import "./models.tsp";
import "./response.tsp";
import "./options.tsp";
using TypeSpec.Http;
using TypeSpec.Versioning;
using Models;
using Responses;
using Options;
/**
* A service to simplify truth expressions, and generate truth tables.
*/
@service({
title: "Simplify Truth API",
})
@versioned(Version)
namespace SimplifyTruths;
enum Version {
v2
v2,
}
@versioned(Version)
@service({
title: "Simplify Truth Expressions",
description: "Simplify truth expressions",
})
namespace Simplify {
model SimplifyResponse {
before: string;
after: string;
orderOfOperations?: string[] = [];
expression: Expression;
}
@tag("Common")
interface Index {
/**
* Information about this API.
*/
@get
@summary("Information")
index(): InfoResponse;
model SimplifyOptions {
lang: "en" | "nb" = "en";
simplify: boolean = true;
caseSensitive: boolean = false;
}
/**
* The OpenAPI specification for this API.
*/
@get
@route("/openapi")
@summary("The OpenAPI specification")
openAPI(): HTML;
@route("/simplify")
interface Simplify {
@get op simplify(
@path exp: string,
@query query?: SimplifyOptions
): SimplifyResponse;
}
/**
* Check if an expression is valid.
*/
@get
@tag("Expression")
@route("/is-valid")
@summary("Check if an expression is valid")
isValid(@path exp: string): IsValidResponse;
}
@tag("Expression")
@route("/simplify")
interface Simplify {
@get
@summary("Simplify a truth expression")
simplify(@path exp: string, @query query?: SimplifyOptions): SimplifyResponse;
@get
@tag("Table")
@route("/table")
@summary("Simplify and generate a truth table")
simplifyTable(
@path exp: string,
@query query?: SimplifyTableOptions,
): SimplifyTableResponse;
}
@tag("Table")
@route("/table")
interface TruthTable {
@get
@summary("Generate a truth table")
simplify(@path exp: string, @query query?: TableOptions): TruthTableResponse;
}

View File

@ -3,29 +3,50 @@ using TypeSpec.OpenAPI;
namespace Models;
@summary("A binary operator")
enum BinaryOperator {
AND,
OR,
IMPLICATION
AND,
OR,
IMPLICATION,
}
@summary("The inverse of an expression")
model ExpressionNot {
not: Expression;
@summary("The expression to negate")
not: Expression;
}
@summary("A binary expression")
model ExpressionBinary {
left: Expression;
operator: BinaryOperator;
right: Expression;
@summary("The left expression")
left: Expression;
@summary("The binary operator")
operator: BinaryOperator;
@summary("The right expression")
right: Expression;
}
@summary("An atomic expression")
model ExpressionAtomic {
atomic: string;
@summary("The atomic value")
atomic: string;
}
@oneOf
@summary("A truth expression")
union Expression {
ExpressionNot;
ExpressionBinary;
ExpressionAtomic;
}
ExpressionNot,
ExpressionBinary,
ExpressionAtomic,
}
@summary("A truth table")
model TruthTable {
@summary("The header of the truth table")
header: string[];
@summary("The rows and columns of the truth table")
truthMatrix: boolean[][];
}

46
spec/options.tsp Normal file
View File

@ -0,0 +1,46 @@
namespace Options;
@summary("Options for simplifying an expression")
model SimplifyOptions {
@summary("Whether to simplify the expression")
simplify?: boolean = true;
@summary("Whether to ignore case when simplifying")
ignoreCase?: boolean = false;
}
@summary("Sort order for a truth table")
enum Sort {
DEFAULT,
TRUE_FIRST,
FALSE_FIRST,
}
@summary("Whether to hide specific rows in a truth table")
enum Hide {
NONE,
TRUE,
FALSE,
}
@summary("Options for generating a truth table")
model TableOptions {
@summary("Sort order for the truth table")
sort?: Sort = Sort.DEFAULT;
@summary("Hide specific rows in the truth table")
hide?: Hide = Hide.NONE;
/**
* Hide intermediate steps when generating the truth table
* For example in the expression "A and B or C", the intermediate step is: A and B
*/
@summary("Hide intermediate steps when generating the truth table")
hideIntermediateSteps?: boolean = false;
}
@summary("Options for simplifying an expression and generating a truth table")
model SimplifyTableOptions {
...SimplifyOptions;
...TableOptions;
}

View File

@ -5,7 +5,8 @@
"author": "Martin Berg Alstad",
"scripts": {
"tsp-compile": "tsp compile . --output-dir dist",
"redoc-build": "redocly build-docs dist/@typespec/openapi3/openapi.v2.yaml --output ../src/resources/static/openapi.html"
"redoc-build": "redocly build-docs dist/@typespec/openapi3/openapi.v2.yaml --output ../src/resources/static/openapi.html",
"tsp-format": "tsp format \"**/*.tsp\""
},
"dependencies": {
"@typespec/compiler": "latest",

69
spec/response.tsp Normal file
View File

@ -0,0 +1,69 @@
import "@typespec/http";
import "./models.tsp";
using TypeSpec.Http;
using Models;
namespace Responses;
/**
* Returns a response as HTML, with the content type set to "text/html".
*/
@summary("Returns a response as HTML")
model HTML {
@header contentType: "text/html";
@body _: string;
}
/**
* Information about this API.
*/
@summary("Information")
model InfoResponse {
message: string;
docs: string;
createdBy: string;
}
/**
* If an expression is valid.
*/
@summary("If an expression is valid")
model IsValidResponse {
isValid: boolean;
}
/**
* Response after simplifying an expression.
*/
@summary("Simplify Response")
model SimplifyResponse {
@summary("Before simplification")
before: string;
@summary("After simplification")
after: string;
@summary("Steps taken to simplify")
operations: string[];
@summary("The simplified expression")
expression: Expression;
}
/**
* Response after generating a truth table.
*/
@summary("Truth Table Response")
model TruthTableResponse {
@summary("The truth table")
truthTable: Models.TruthTable;
}
/**
* Response after simplifying an expression and generating a truth table.
*/
@summary("Simplify and Table Response")
model SimplifyTableResponse {
...SimplifyResponse;
...TruthTableResponse;
}

View File

@ -112,7 +112,7 @@ impl TruthTable {
return vec![];
}
atomics.sort();
Self::truth_combinations(atomics.len()).iter()
Self::truth_combinations(atomics.len() as u32).iter()
.filter_map(|combo| {
let expression = Self::resolve_expression(expression, &atomics.iter()
.enumerate()
@ -127,12 +127,13 @@ impl TruthTable {
}).collect()
}
fn truth_combinations(count: usize) -> TruthMatrix {
(0..2usize.pow(count as u32))
.map(|i| (0..count).rev()
// Just trust me bro
.map(|j| (i >> j) & 1 == 0).collect()
).collect()
fn truth_combinations(count: u32) -> TruthMatrix {
let row_len = 2usize.pow(count);
let rows = 0..row_len;
rows.map(|index| (0..count).rev()
// Just trust me bro
.map(|shift| (index >> shift) & 1 == 0).collect()
).collect()
}
fn resolve_expression(expression: &Expression, booleans: &HashMap<String, bool>, header: &[String], hide_intermediate: bool) -> Vec<bool> {

View File

@ -1,15 +1,14 @@
use std::net::SocketAddr;
use axum::{ServiceExt};
use axum::extract::Request;
use lib::{create_app, join_routes};
use axum::extract::Request;
use axum::ServiceExt;
use lib::{create_app, join_routes};
use tokio::net::TcpListener;
use tower::Layer;
use tower_http::cors::{Any, CorsLayer};
use tower_http::normalize_path::NormalizePathLayer;
use tower_http::trace;
use tower_http::trace::TraceLayer;
use tower::Layer;
use tracing::Level;
use crate::routing::routes::*;

File diff suppressed because one or more lines are too long