├── .gitignore ├── ui ├── .gitignore ├── .babelrc ├── app │ ├── QueryEditor │ │ ├── types.ts │ │ ├── Nothing.tsx │ │ ├── SelectKind.tsx │ │ ├── BinaryComponent.tsx │ │ ├── Layer.tsx │ │ └── Term.tsx │ ├── reducer │ │ ├── isAdvanced.ts │ │ ├── results.ts │ │ ├── available.ts │ │ ├── advanced.ts │ │ ├── higherOrder.ts │ │ ├── structuredHighlights.ts │ │ └── structuredQuery.ts │ ├── index.tsx │ ├── queryApi.ts │ ├── index.scss │ ├── QueryBuilder.tsx │ ├── reducer.ts │ ├── AdvancedInput.tsx │ ├── Page.tsx │ ├── QueryEditor.tsx │ ├── sagas.ts │ ├── HighlightBuilder.tsx │ ├── selectors.ts │ ├── ResultList.tsx │ ├── types.ts │ └── actions.ts ├── tsconfig.json ├── package.json └── webpack.config.js ├── examples └── data │ ├── basic_generic.rs │ └── hello_world.rs ├── .travis.yml ├── Cargo.toml ├── LICENSE-MIT ├── README.md ├── src └── bin │ ├── indexer.rs │ └── server.rs ├── LICENSE-APACHE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /ui/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /examples/data/basic_generic.rs: -------------------------------------------------------------------------------- 1 | trait Foo {} 2 | 3 | fn bar(t: T) 4 | where T: Foo, 5 | {} 6 | -------------------------------------------------------------------------------- /examples/data/hello_world.rs: -------------------------------------------------------------------------------- 1 | // This is an example program 2 | fn main() { 3 | println!("Hello, world!"); 4 | } 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: nightly 3 | cache: cargo 4 | sudo: false 5 | script: | 6 | cargo build 7 | cargo test 8 | cargo run --bin=indexer examples/data/hello_world.rs > /dev/null 9 | -------------------------------------------------------------------------------- /ui/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["@babel/proposal-object-rest-spread"], 3 | "presets": [ 4 | ["@babel/env", { 5 | "targets": { 6 | "browsers": "last 2 versions, not ie < 11", 7 | }, 8 | "modules": false, 9 | }], 10 | "@babel/react", 11 | ], 12 | } 13 | -------------------------------------------------------------------------------- /ui/app/QueryEditor/types.ts: -------------------------------------------------------------------------------- 1 | import { Kind } from "app/types"; 2 | 3 | export interface QueryEventHandlers { 4 | onKindChange: (id: number, kind: Kind) => any; 5 | onLayerChange: (id: number, layer: string) => any; 6 | onTermNameChange: (id: number, layer: string) => any; 7 | onTermValueChange: (id: number, layer: string) => any; 8 | } 9 | -------------------------------------------------------------------------------- /ui/app/reducer/isAdvanced.ts: -------------------------------------------------------------------------------- 1 | import { ActionType, Action } from 'app/actions'; 2 | 3 | export type State = boolean; 4 | 5 | export default function isAdvanced(state = false, action: Action): State { 6 | switch (action.type) { 7 | case ActionType.QueryToggle: 8 | return !state; 9 | default: 10 | return state; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Jake Goulding "] 3 | name = "ebene_rs" 4 | version = "0.1.0" 5 | 6 | [dependencies] 7 | lazy_static = "1.0" 8 | quick-error = "1.1" 9 | rocket = "0.4.0" 10 | rocket_codegen = "0.4.0" 11 | rocket_contrib = "0.4.0" 12 | serde = "1.0" 13 | serde_derive = "1.0" 14 | serde_json = "1.0" 15 | fuzzy-pickles = "0.1.0" 16 | ebene = "0.2.0" 17 | -------------------------------------------------------------------------------- /ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "baseUrl": "./", 5 | "paths": { 6 | "app": ["app"] 7 | }, 8 | "sourceMap": true, 9 | "noImplicitAny": true, 10 | "module": "commonjs", 11 | "target": "es2017", 12 | "strict": true, 13 | "noErrorTruncation": true, 14 | "jsx": "react" 15 | }, 16 | "include": [ 17 | "./app/**/*" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /ui/app/QueryEditor/Nothing.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Kind } from 'app/types'; 4 | 5 | import { QueryEventHandlers } from './types'; 6 | import SelectKind from './SelectKind'; 7 | 8 | interface NothingProps { 9 | id: number, 10 | kind: Kind, 11 | handlers: QueryEventHandlers; 12 | } 13 | 14 | const Nothing: React.SFC = ({ id, kind, handlers }) => ( 15 |
16 | 17 |
18 | ); 19 | 20 | export default Nothing; 21 | -------------------------------------------------------------------------------- /ui/app/reducer/results.ts: -------------------------------------------------------------------------------- 1 | import { ActionType, Action } from 'app/actions'; 2 | import { QueryResult } from 'app/types'; 3 | 4 | export type State = QueryResult[]; 5 | 6 | const initialState: State = [] 7 | 8 | export default function results(state = initialState, action: Action): State { 9 | switch (action.type) { 10 | case ActionType.QueryResults: 11 | if (!action.error) { 12 | return action.payload.results; 13 | } else { 14 | return state; 15 | } 16 | default: 17 | return state; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ui/app/QueryEditor/SelectKind.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Kind } from '../types'; 4 | import { QueryEventHandlers } from './types'; 5 | 6 | interface SelectKindProps { 7 | id: number, 8 | kind: Kind, 9 | onKindChange: QueryEventHandlers['onKindChange']; 10 | } 11 | 12 | const SelectKind: React.SFC = ({ id, kind, onKindChange }) => ( 13 | 18 | ); 19 | 20 | export default SelectKind; 21 | -------------------------------------------------------------------------------- /ui/app/reducer/available.ts: -------------------------------------------------------------------------------- 1 | import { ActionType, Action } from 'app/actions'; 2 | 3 | export interface State { 4 | layers: string[]; 5 | terms: string[]; 6 | } 7 | 8 | const initialState: State = { 9 | layers: [], 10 | terms: [], 11 | }; 12 | 13 | export default function available(state = initialState, action: Action): State { 14 | switch (action.type) { 15 | case ActionType.AvailableLayersUpdate: { 16 | return { ...state, layers: action.payload.layers }; 17 | } 18 | case ActionType.AvailableTermsUpdate: { 19 | return { ...state, terms: action.payload.terms }; 20 | } 21 | default: 22 | return state; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ui/app/reducer/advanced.ts: -------------------------------------------------------------------------------- 1 | import { ActionType, Action } from 'app/actions'; 2 | 3 | export interface State { 4 | query: string; 5 | highlight: string; 6 | } 7 | 8 | const initialState: State = { 9 | query: '{"Layer": {"name": "function"}}', 10 | highlight: '[{"Term": {"name": "ident", "value": "pm"}}]', 11 | }; 12 | 13 | export default function advanced(state = initialState, action: Action): State { 14 | switch (action.type) { 15 | case ActionType.AdvancedQueryUpdate: { 16 | const { query } = action.payload; 17 | return { ...state, query }; 18 | } 19 | case ActionType.AdvancedHighlightUpdate: { 20 | const { highlight } = action.payload; 21 | return { ...state, highlight }; 22 | } 23 | default: 24 | return state; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /ui/app/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import { createStore, applyMiddleware, compose } from 'redux'; 5 | import createSagaMiddleware from 'redux-saga'; 6 | 7 | import Page from './Page'; 8 | import reducer from './reducer'; 9 | import saga from './sagas'; 10 | 11 | import 'normalize.css'; 12 | import './index.scss'; 13 | 14 | const sagaMiddleware = createSagaMiddleware(); 15 | 16 | const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; 17 | const store = createStore(reducer, {}, composeEnhancers( 18 | applyMiddleware(sagaMiddleware) 19 | )); 20 | 21 | sagaMiddleware.run(saga); 22 | 23 | ReactDOM.render( 24 | 25 | 26 | , 27 | document.getElementById('app') 28 | ); 29 | -------------------------------------------------------------------------------- /ui/app/QueryEditor/BinaryComponent.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Kind, TreeQueryItem } from 'app/types'; 4 | 5 | import QueryEditor from '../QueryEditor'; 6 | import { QueryEventHandlers } from './types'; 7 | import SelectKind from './SelectKind'; 8 | 9 | interface BinaryComponentProps { 10 | id: number, 11 | kind: Kind, 12 | lhs: TreeQueryItem, 13 | rhs: TreeQueryItem, 14 | handlers: QueryEventHandlers; 15 | } 16 | 17 | const BinaryComponent: React.SFC = ({ id, kind, lhs, rhs, handlers }) => ( 18 |
19 | 20 |
21 | 22 | 23 |
24 |
25 | ); 26 | 27 | export default BinaryComponent; 28 | -------------------------------------------------------------------------------- /ui/app/queryApi.ts: -------------------------------------------------------------------------------- 1 | import * as url from 'url'; 2 | 3 | import { QueryResult } from "./types"; 4 | 5 | interface ApiLayersResponse { 6 | layers: string[]; 7 | } 8 | 9 | export async function fetchLayers(): Promise { 10 | let resp = await fetch('/api/dev/layers'); 11 | return resp.json(); 12 | } 13 | 14 | interface ApiTermsResponse { 15 | terms: string[]; 16 | } 17 | 18 | export async function fetchTerms(): Promise { 19 | let resp = await fetch('/api/dev/terms'); 20 | return resp.json(); 21 | } 22 | 23 | interface QueryArgs { 24 | q?: string; 25 | h?: string; 26 | } 27 | 28 | interface ApiQueryResponse { 29 | results: QueryResult[]; 30 | } 31 | 32 | export default async function primaryQuery({ q, h }: QueryArgs): Promise { 33 | const apiUrl = url.format({ 34 | pathname: '/api/search', 35 | query: { q, h }, 36 | }); 37 | 38 | let resp = await fetch(apiUrl); 39 | return resp.json(); 40 | } 41 | -------------------------------------------------------------------------------- /ui/app/reducer/higherOrder.ts: -------------------------------------------------------------------------------- 1 | import { isWithTarget, isWithTargetIndex } from 'app/actions'; 2 | 3 | export const forTarget = (reducer: (s: S, a: A) => S, target: string) => 4 | (state: S, action: A) => 5 | isWithTarget(action) && action.meta.target === target ? reducer(state, action) : state; 6 | 7 | export const forTargetIndex = (reducer: (state: S, action: A) => S) => 8 | (state: S[], action: A) => { 9 | if (isWithTargetIndex(action) && action.meta.targetIndex < state.length) { 10 | const index = action.meta.targetIndex; 11 | const result = reducer(state[index], action); 12 | const newState = state.slice(); 13 | newState.splice(index, 1, result); 14 | return newState; 15 | } else { 16 | return state; 17 | } 18 | } 19 | 20 | export const initial = (reducer: (s: S, a: A) => S, initialState: S) => 21 | (state: S | undefined, action: A) => 22 | reducer(state || initialState, action); 23 | -------------------------------------------------------------------------------- /ui/app/reducer/structuredHighlights.ts: -------------------------------------------------------------------------------- 1 | import { ActionType, Action } from 'app/actions'; 2 | import { Kind, FlatQueryItems, makeNothing } from 'app/types'; 3 | 4 | import { forTarget, forTargetIndex } from './higherOrder'; 5 | import { rawReducer } from './structuredQuery'; 6 | 7 | const structuredHighlightReducer = forTarget(forTargetIndex(rawReducer), 'highlight'); 8 | 9 | export type State = FlatQueryItems[]; 10 | 11 | const initialStructuredHighlight: State = [{ 12 | 0: { kind: Kind.Term, name: 'ident', value: 'pm' }, 13 | }]; 14 | 15 | export default function structuredHighlightsReducer(state = initialStructuredHighlight, action: Action): State { 16 | switch (action.type) { 17 | case ActionType.HighlightAdd: { 18 | const { index } = action.payload; 19 | const newState = state.slice(); 20 | newState.splice(index + 1, 0, { 0: makeNothing() }); 21 | return newState; 22 | } 23 | default: 24 | return structuredHighlightReducer(state, action); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ui/app/index.scss: -------------------------------------------------------------------------------- 1 | .structured-query { 2 | &__child { 3 | padding-left: 0.5em; 4 | } 5 | } 6 | 7 | .layers { 8 | position: relative; 9 | 10 | &-layer { 11 | margin: 0; 12 | } 13 | 14 | &-highlight { 15 | position: absolute; 16 | top: 0; 17 | bottom: 0; 18 | left: 0; 19 | right: 0; 20 | 21 | /* Don't bother showing this text */ 22 | color: rgba(0, 0, 0, 0); 23 | } 24 | } 25 | 26 | .layers-highlight-0 .highlight { 27 | background-color: rgba(255, 0, 0, 0.5); 28 | } 29 | 30 | .layers-highlight-1 .highlight { 31 | background-color: rgba(0, 255, 0, 0.5); 32 | } 33 | 34 | .layers-highlight-2 .highlight { 35 | background-color: rgba(0, 0, 255, 0.5); 36 | } 37 | 38 | .layers-highlight-3 .highlight { 39 | background-color: rgba(255, 255, 0, 0.5); 40 | } 41 | 42 | .layers-highlight-4 .highlight { 43 | background-color: rgba(0, 255, 255, 0.5); 44 | } 45 | 46 | .layers-highlight-5 .highlight { 47 | background-color: rgba(255, 0, 255, 0.5); 48 | } 49 | -------------------------------------------------------------------------------- /ui/app/QueryBuilder.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { bindActionCreators, ActionCreator, Dispatch } from 'redux'; 4 | 5 | import { selectTreeQuery } from 'app/selectors'; 6 | import { updateKind, updateLayerName, updateTermName, updateTermValue, withTarget, Action } from 'app/actions'; 7 | 8 | import QueryEditor from './QueryEditor'; 9 | import { State } from './reducer'; 10 | 11 | const mapStateToProps = (state: State) => selectTreeQuery(state.structuredQuery); 12 | 13 | const targetMe = (action: ActionCreator) => withTarget(action, 'query'); 14 | 15 | const mapDispatchToProps = (dispatch: Dispatch) => ({ 16 | handlers: bindActionCreators({ 17 | onKindChange: targetMe(updateKind), 18 | onLayerChange: targetMe(updateLayerName), 19 | onTermNameChange: targetMe(updateTermName), 20 | onTermValueChange: targetMe(updateTermValue), 21 | }, dispatch) 22 | }); 23 | 24 | export default connect( 25 | mapStateToProps, 26 | mapDispatchToProps 27 | )(QueryEditor); 28 | -------------------------------------------------------------------------------- /ui/app/reducer.ts: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | 3 | import { Kind } from 'app/types'; 4 | import { ActionType, Action } from 'app/actions'; 5 | 6 | import advanced, { State as AdvancedState } from './reducer/advanced'; 7 | import available, { State as AvailableState } from './reducer/available'; 8 | import isAdvanced, { State as IsAdvancedState } from './reducer/isAdvanced'; 9 | import results, { State as ResultsState } from './reducer/results'; 10 | import structuredHighlights, { State as StructuredHighlightsState } from './reducer/structuredHighlights'; 11 | import structuredQuery, { State as StructuredQueryState } from './reducer/structuredQuery'; 12 | 13 | export interface State { 14 | advanced: AdvancedState, 15 | available: AvailableState, 16 | isAdvanced: IsAdvancedState, 17 | results: ResultsState, 18 | structuredHighlights: StructuredHighlightsState, 19 | structuredQuery: StructuredQueryState, 20 | } 21 | 22 | export default combineReducers({ 23 | advanced, 24 | available, 25 | isAdvanced, 26 | results, 27 | structuredHighlights, 28 | structuredQuery, 29 | }); 30 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Jake Goulding 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /ui/app/AdvancedInput.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { connect } from 'react-redux'; 3 | 4 | import { updateAdvancedQuery, updateAdvancedHighlight } from 'app/actions'; 5 | import { State } from 'app/reducer'; 6 | 7 | interface AdvancedInputProps { 8 | query: string; 9 | highlight: string; 10 | onQueryChange: (_: string) => any; 11 | onHighlightChange: (_: string) => any; 12 | } 13 | 14 | const AdvancedInput: React.SFC = ({ query, highlight, onQueryChange, onHighlightChange }) => ( 15 |
16 | 19 | 22 |
23 | ); 24 | 25 | const mapStateToProps = ({ advanced: { query, highlight } }: State) => ({ 26 | query, 27 | highlight, 28 | }); 29 | 30 | const mapDispatchToProps = { 31 | onQueryChange: updateAdvancedQuery, 32 | onHighlightChange: updateAdvancedHighlight, 33 | }; 34 | 35 | export default connect( 36 | mapStateToProps, 37 | mapDispatchToProps 38 | )(AdvancedInput); 39 | -------------------------------------------------------------------------------- /ui/app/QueryEditor/Layer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { connect } from 'react-redux'; 3 | 4 | import { Kind } from 'app/types'; 5 | import { selectAvailableLayers, selectLayerValid } from 'app/selectors'; 6 | import { State } from 'app/reducer'; 7 | 8 | import SelectKind from './SelectKind'; 9 | import { QueryEventHandlers } from './types'; 10 | 11 | interface LayerProps extends LayerOwnProps { 12 | id: number, 13 | kind: Kind, 14 | layers: string[], 15 | isValid: boolean, 16 | handlers: QueryEventHandlers, 17 | } 18 | 19 | const Layer: React.SFC = ({ id, kind, name, layers, isValid, handlers }) => ( 20 |
21 | 22 | 26 |
27 | ); 28 | 29 | interface LayerOwnProps { 30 | name: string; 31 | } 32 | 33 | const mapStateToProps = (state: State, props: LayerOwnProps) => ({ 34 | isValid: selectLayerValid(state, props.name), 35 | layers: selectAvailableLayers(state), 36 | }); 37 | 38 | export default connect(mapStateToProps)(Layer); 39 | -------------------------------------------------------------------------------- /ui/app/Page.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { connect } from 'react-redux'; 3 | 4 | import { QueryResult } from 'app/types'; 5 | import { State } from 'app/reducer'; 6 | import { toggleAdvanced } from 'app/actions'; 7 | 8 | import AdvancedInput from './AdvancedInput'; 9 | import HighlightBuilder from './HighlightBuilder'; 10 | import QueryBuilder from './QueryBuilder'; 11 | import ResultList from './ResultList'; 12 | 13 | interface InputProps { 14 | isAdvanced: boolean; 15 | } 16 | 17 | const Input: React.SFC = ({ isAdvanced }) => ( 18 | isAdvanced ? :
19 | ); 20 | 21 | interface PageProps { 22 | isAdvanced: boolean; 23 | results: QueryResult[]; 24 | toggleAdvanced: () => any; 25 | } 26 | 27 | const Page: React.SFC = ({ isAdvanced, results, toggleAdvanced }) => ( 28 |
29 | 30 | 31 | 32 |
33 | ); 34 | 35 | const mapStateToProps = ({ isAdvanced, results }: State) => ({ 36 | isAdvanced, 37 | results, 38 | }); 39 | 40 | const mapDispatchToProps = { 41 | toggleAdvanced, 42 | }; 43 | 44 | export default connect( 45 | mapStateToProps, 46 | mapDispatchToProps, 47 | )(Page); 48 | -------------------------------------------------------------------------------- /ui/app/QueryEditor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Kind, TreeQueryItem } from 'app/types'; 4 | 5 | import { QueryEventHandlers } from './QueryEditor/types'; 6 | import BinaryComponent from './QueryEditor/BinaryComponent'; 7 | import Layer from './QueryEditor/Layer'; 8 | import Nothing from './QueryEditor/Nothing'; 9 | import SelectKind from './QueryEditor/SelectKind'; 10 | import Term from './QueryEditor/Term'; 11 | 12 | const mapKindToComponent = { 13 | [Kind.Nothing]: Nothing, 14 | [Kind.Layer]: Layer, 15 | [Kind.Term]: Term, 16 | [Kind.Containing]: BinaryComponent, 17 | [Kind.ContainedIn]: BinaryComponent, 18 | [Kind.NotContaining]: BinaryComponent, 19 | [Kind.NotContainedIn]: BinaryComponent, 20 | [Kind.OneOf]: BinaryComponent, 21 | [Kind.BothOf]: BinaryComponent, 22 | [Kind.FollowedBy]: BinaryComponent, 23 | }; 24 | 25 | interface QueryEditorProps { 26 | handlers: QueryEventHandlers, 27 | } 28 | 29 | const QueryEditor: React.SFC = (props) => { 30 | const Component = mapKindToComponent[props.kind]; 31 | return ( 32 |
33 | { /* My TypeScript foo is not good enough 34 | // @ts-ignore */ } 35 | 36 |
37 | ); 38 | }; 39 | 40 | export default QueryEditor; 41 | -------------------------------------------------------------------------------- /ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "babel-polyfill": "^6.22.0", 8 | "normalize.css": "^8.0.0", 9 | "react": "^16.4.0", 10 | "react-dom": "^16.4.0", 11 | "react-redux": "^6.0.1", 12 | "redux": "^4.0.0", 13 | "redux-saga": "^1.0.1", 14 | "url": "^0.11.0" 15 | }, 16 | "devDependencies": { 17 | "@babel/cli": "^7.2.3", 18 | "@babel/core": "^7.3.4", 19 | "@babel/plugin-proposal-object-rest-spread": "^7.3.4", 20 | "@babel/preset-env": "^7.3.4", 21 | "@babel/preset-react": "^7.0.0", 22 | "@types/node": "^11.9.5", 23 | "@types/react": "^16.3.16", 24 | "@types/react-dom": "^16.0.6", 25 | "@types/react-redux": "^6.0.2", 26 | "awesome-typescript-loader": "^5.0.0", 27 | "babel-loader": "^8.0.5", 28 | "css-loader": "^2.1.0", 29 | "html-webpack-plugin": "^3.2.0", 30 | "html-webpack-template": "^6.0.0", 31 | "node-sass": "^4.3.0", 32 | "sass-loader": "^7.0.3", 33 | "source-map-loader": "^0.2.3", 34 | "style-loader": "^0.23.1", 35 | "typescript": "^3.3.3333", 36 | "webpack": "^4.11.0", 37 | "webpack-cli": "^3.0.3", 38 | "webpack-dev-server": "^3.1.4" 39 | }, 40 | "scripts": { 41 | "build": "webpack --mode development", 42 | "serve": "webpack-dev-server --mode development" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ui/app/QueryEditor/Term.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { connect } from 'react-redux'; 3 | 4 | import { selectTermValid, selectAvailableTerms } from 'app/selectors'; 5 | import { Kind } from 'app/types'; 6 | 7 | import SelectKind from './SelectKind'; 8 | import { QueryEventHandlers } from './types'; 9 | import { State } from '../reducer'; 10 | 11 | interface TermProps extends TermOwnProps { 12 | id: number, 13 | kind: Kind, 14 | value: string, 15 | terms: string[], 16 | isValid: boolean, 17 | handlers: QueryEventHandlers, 18 | } 19 | 20 | const Term: React.SFC = ({ id, kind, name, value, terms, isValid, handlers }) => ( 21 |
22 | 23 | 27 | : 28 | handlers.onTermValueChange(id, e.target.value)}> 29 |
30 | ); 31 | 32 | interface TermOwnProps { 33 | name: string, 34 | } 35 | 36 | const mapStateToProps = (state: State, props: TermOwnProps) => ({ 37 | isValid: selectTermValid(state, props.name), 38 | terms: selectAvailableTerms(state), 39 | }); 40 | 41 | export default connect(mapStateToProps)(Term); 42 | -------------------------------------------------------------------------------- /ui/app/sagas.ts: -------------------------------------------------------------------------------- 1 | import { 2 | all, 3 | call, 4 | fork, 5 | put, 6 | select, 7 | spawn, 8 | takeEvery, 9 | takeLatest, 10 | } from 'redux-saga/effects'; 11 | 12 | import { 13 | ActionType, 14 | queryFailed, 15 | updateAvailableLayers, 16 | updateAvailableTerms, 17 | updateQueryResults, 18 | } from './actions'; 19 | import { selectQuery } from './selectors'; 20 | import search, { fetchLayers, fetchTerms } from './queryApi'; 21 | 22 | function* performSearch() { 23 | try { 24 | const q = yield select(selectQuery); 25 | const { results } = yield call(search, q); 26 | yield put(updateQueryResults(results)); 27 | } catch (e) { 28 | yield put(queryFailed(e.message)); 29 | } 30 | } 31 | 32 | function* watchForSearchUpdates() { 33 | yield takeEvery(ActionType.AdvancedQueryUpdate, performSearch); 34 | yield takeEvery(ActionType.AdvancedHighlightUpdate, performSearch); 35 | yield takeEvery(ActionType.StructuredQueryKindUpdate, performSearch); 36 | yield takeEvery(ActionType.LayerNameUpdate, performSearch); 37 | yield takeEvery(ActionType.TermNameUpdate, performSearch); 38 | yield takeEvery(ActionType.TermValueUpdate, performSearch); 39 | } 40 | 41 | function* loadInitialData() { 42 | let [layers, terms] = yield all([ 43 | call(fetchLayers), 44 | call(fetchTerms), 45 | ]); 46 | yield put(updateAvailableLayers(layers)); 47 | yield put(updateAvailableTerms(terms)); 48 | } 49 | 50 | export default function* main() { 51 | yield spawn(loadInitialData); 52 | yield fork(watchForSearchUpdates); 53 | } 54 | -------------------------------------------------------------------------------- /ui/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const HtmlWebpackTemplate = require('html-webpack-template'); 5 | 6 | module.exports = { 7 | plugins: [ 8 | new HtmlWebpackPlugin({ 9 | template: HtmlWebpackTemplate, 10 | title: 'Ebene Rust', 11 | appMountId: 'app', 12 | mobile: true, 13 | inject: false, 14 | }), 15 | ], 16 | resolve: { 17 | alias: { 18 | app: path.resolve(__dirname, "app"), 19 | }, 20 | extensions: ['.js', '.jsx', '.ts', '.tsx'], 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.tsx?$/, 26 | loader: "awesome-typescript-loader", 27 | }, 28 | { 29 | enforce: "pre", 30 | test: /\.js$/, 31 | loader: "source-map-loader", 32 | }, 33 | { 34 | test: /\.jsx?$/, 35 | loader: 'babel-loader', 36 | options: { 37 | // Improved performance during development. 38 | cacheDirectory: true, 39 | }, 40 | }, 41 | { 42 | test: /\.scss$/, 43 | loaders: ["style-loader", "css-loader", "sass-loader"] 44 | }, 45 | { 46 | test: /\.css$/, 47 | loaders: ["style-loader", "css-loader"] 48 | }, 49 | ], 50 | }, 51 | entry: ['babel-polyfill', './app/index.tsx'], 52 | output: { 53 | filename: 'bundle.js', 54 | path: path.resolve(__dirname, './dist'), 55 | }, 56 | devServer: { 57 | proxy: { 58 | '/api': { 59 | target: 'http://127.0.0.1:8000/', 60 | secure: false, 61 | pathRewrite: {'^/api' : ''}, 62 | } 63 | } 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /ui/app/HighlightBuilder.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { bindActionCreators, Dispatch, ActionCreator } from 'redux'; 4 | 5 | import { selectTreeQuery } from 'app/selectors'; 6 | import { 7 | highlightAdd, 8 | withTarget, 9 | withTargetIndex, 10 | updateKind, 11 | updateLayerName, 12 | updateTermName, 13 | updateTermValue, 14 | Action, 15 | } from 'app/actions'; 16 | import { State } from 'app/reducer'; 17 | import { TreeQueryItem } from 'app/types'; 18 | 19 | import QueryEditor from './QueryEditor'; 20 | import { QueryEventHandlers } from './QueryEditor/types'; 21 | 22 | type HighlightOneUnconnectedProps = TreeQueryItem & HighlightOwnProps & { 23 | onAddHighlight: () => any, 24 | handlers: QueryEventHandlers, 25 | } 26 | 27 | // Extracting `index` to prevent passing it down further 28 | const HighlightOneUnconnected: React.SFC = ({ index, onAddHighlight, ...props }) => ( 29 |
30 |
33 | ); 34 | 35 | const targetMe = (action: ActionCreator, index: number) => withTarget(withTargetIndex(action, index), 'highlight'); 36 | 37 | interface HighlightOwnProps { 38 | index: number; 39 | } 40 | 41 | const mapDispatchToProps = (dispatch: Dispatch, { index }: HighlightOwnProps) => ({ 42 | handlers: bindActionCreators({ 43 | onKindChange: targetMe(updateKind, index), 44 | onLayerChange: targetMe(updateLayerName, index), 45 | onTermNameChange: targetMe(updateTermName, index), 46 | onTermValueChange: targetMe(updateTermValue, index), 47 | }, dispatch), 48 | onAddHighlight: () => dispatch(highlightAdd(index)), 49 | }); 50 | 51 | const HighlightOne = connect( 52 | null, 53 | mapDispatchToProps 54 | )(HighlightOneUnconnected); 55 | 56 | 57 | interface HighlightsProps { 58 | highlights: TreeQueryItem[]; 59 | } 60 | 61 | const Highlights: React.SFC = ({ highlights }) => ( 62 |
63 | {highlights.map((h, i) => )} 64 |
65 | ); 66 | 67 | const mapStateToProps = (state: State) => ({ 68 | highlights: state.structuredHighlights.map(selectTreeQuery), 69 | }); 70 | 71 | export default connect( 72 | mapStateToProps, 73 | null 74 | )(Highlights); 75 | -------------------------------------------------------------------------------- /ui/app/selectors.ts: -------------------------------------------------------------------------------- 1 | import { Kind, BinaryKind, FlatQueryItems, TreeQueryItem, ApiQueryItem, ApiBinary } from './types'; 2 | import { State } from './reducer'; 3 | 4 | export function selectQuery(state: State) { 5 | if (state.isAdvanced) { 6 | const { query, highlight } = state.advanced; 7 | return { 8 | q: query, 9 | h: highlight, 10 | }; 11 | } 12 | 13 | const structuredQuery = selectTreeQueryForApi(state.structuredQuery); 14 | const structuredHighlight = state.structuredHighlights.map(selectTreeQueryForApi); 15 | 16 | return { 17 | q: JSON.stringify(structuredQuery), 18 | h: JSON.stringify(structuredHighlight), 19 | }; 20 | } 21 | 22 | function selectTreeQueryForApi(queryList: FlatQueryItems) { 23 | function treeify(id: number): ApiQueryItem { 24 | let thisQuery = queryList[id]; 25 | 26 | switch (thisQuery.kind) { 27 | case Kind.Containing: 28 | case Kind.ContainedIn: 29 | case Kind.NotContaining: 30 | case Kind.NotContainedIn: 31 | case Kind.OneOf: 32 | case Kind.BothOf: 33 | case Kind.FollowedBy: { 34 | let { lhs, rhs } = thisQuery; 35 | return { [thisQuery.kind]: [treeify(lhs), treeify(rhs)] } as ApiBinary; 36 | } 37 | case Kind.Layer: { 38 | const { kind, name } = thisQuery; 39 | return { [thisQuery.kind]: { name } }; 40 | } 41 | case Kind.Term: { 42 | const { kind, name, value } = thisQuery; 43 | return { [thisQuery.kind]: { name, value } }; 44 | } 45 | case Kind.Nothing: 46 | return thisQuery.kind; 47 | }; 48 | } 49 | 50 | return treeify(0); 51 | } 52 | 53 | export function selectTreeQuery(queryList: FlatQueryItems) { 54 | function treeify(id: number): TreeQueryItem { 55 | const thisQuery = queryList[id]; 56 | 57 | switch (thisQuery.kind) { 58 | case Kind.Containing: 59 | case Kind.ContainedIn: 60 | case Kind.NotContaining: 61 | case Kind.NotContainedIn: 62 | case Kind.OneOf: 63 | case Kind.BothOf: 64 | case Kind.FollowedBy: 65 | return { ...thisQuery, id, lhs: treeify(thisQuery.lhs), rhs: treeify(thisQuery.rhs) }; 66 | default: 67 | return { ...thisQuery, id }; 68 | } 69 | } 70 | 71 | return treeify(0); 72 | } 73 | 74 | export const selectAvailableTerms = (state: State) => state.available.terms; 75 | export const selectAvailableLayers = (state: State) => state.available.layers; 76 | 77 | export const selectTermValid = (state: State, term: string) => 78 | selectAvailableTerms(state).includes(term); 79 | export const selectLayerValid = (state: State, layer: string) => 80 | selectAvailableLayers(state).includes(layer); 81 | -------------------------------------------------------------------------------- /ui/app/ResultList.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { QueryResult, Extents } from './types'; 3 | 4 | interface CodeProps { 5 | source: string; 6 | } 7 | 8 | const Code: React.SFC = ({ source }) => ( 9 |
 10 |         {source}
 11 |     
12 | ); 13 | 14 | function* flattenExtents(extents: Extents) { 15 | for (const [start, end] of extents) { 16 | yield start; 17 | yield end; 18 | } 19 | } 20 | 21 | function* sourceCutpoints(source: string, extents: Extents) { 22 | yield 0; 23 | yield* flattenExtents(extents); 24 | yield source.length; 25 | } 26 | 27 | function* highlightedSourceWindows(source: string, extents: Extents): IterableIterator<[boolean, string]> { 28 | const p = sourceCutpoints(source, extents); 29 | let start: number | undefined = undefined; 30 | let end: number | undefined = undefined; 31 | let highlight = false; 32 | 33 | for (const i of p) { 34 | start = end; 35 | end = i; 36 | if (start === undefined || end == undefined) { continue; } 37 | 38 | const s = source.slice(start, end); 39 | yield [highlight, s]; 40 | highlight = !highlight; 41 | } 42 | } 43 | 44 | interface LayerProps { 45 | source: string; 46 | extents: Extents; 47 | index: number; 48 | } 49 | 50 | const Layer: React.SFC = ({ source, extents, index }) => { 51 | const pieces: (string | JSX.Element)[] = []; 52 | let count = 0; 53 | 54 | for (const [highlight, text] of highlightedSourceWindows(source, extents)) { 55 | if (highlight) { 56 | pieces.push({text}); 57 | } else { 58 | pieces.push(text); 59 | } 60 | count++; 61 | } 62 | 63 | return ( 64 |
 65 |             
 66 |                 {pieces}
 67 |             
 68 |         
69 | ); 70 | }; 71 | 72 | interface ResultProps { 73 | source: QueryResult['text']; 74 | highlights: QueryResult['highlights']; 75 | } 76 | 77 | const Result: React.SFC = ({ source, highlights }) => { 78 | const layers = highlights.map((highlight, i) => ( 79 | 80 | )); 81 | 82 | return ( 83 |
84 | 85 | {layers} 86 |
87 | ); 88 | }; 89 | 90 | interface ResultListProps { 91 | results: QueryResult[]; 92 | } 93 | 94 | const ResultList: React.SFC = ({ results }) => { 95 | const renderedResults = results.map(({ text, highlights }, i) => ( 96 |
  • 97 | )); 98 | 99 | return ( 100 |
    101 | Showing {results.length} results: 102 |
      {renderedResults}
    103 |
    104 | ); 105 | }; 106 | 107 | export default ResultList; 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ebene-Rust 2 | 3 | Ebene-Rust is a unique way of exploring Rust code, aiming to answer 4 | questions like: 5 | 6 | - Which methods take a generic argument that implements the trait `Foo`? 7 | - Do any structs contain a field called `data`? 8 | - What statements come after a "TODO" comment? 9 | - Are weird statements like `let Single { y }: Single<&'static u32>;` ever used? 10 | 11 | ## How do I use it? 12 | 13 | Right now, this project is very much in an alpha state. That's the 14 | polite way of saying "it works on my machine, and probably no 15 | other". I'm hoping to get it into a shape where it at least compiles 16 | in CI soon. 17 | 18 | ## Components 19 | 20 | Ebene-Rust is a combination of many pieces of open source 21 | technology. Some selected pieces include: 22 | 23 | ### Ebene 24 | 25 | [Ebene][] is the underlying search technology that powers the ability 26 | to perform queries based on the structure of the data. These queries 27 | are different from the traditional search engine inverted index and 28 | are based around manipulating ranges of the indexed text known as 29 | "extents". 30 | 31 | The Ebene crate works well on stable Rust. 32 | 33 | [Ebene]: https://github.com/shepmaster/ebene 34 | 35 | ### Fuzzy Pickles 36 | 37 | [Fuzzy Pickles][] is a Rust parser written in Rust, constructed with 38 | the goal of expressing the level of detail needed to power the 39 | underlying search technology. 40 | 41 | Fuzzy Pickles works well on stable Rust. 42 | 43 | [Fuzzy Pickles]: https://github.com/shepmaster/fuzzy-pickles 44 | 45 | ### Web UI 46 | 47 | Although the command line is a wonderful tool, building up the 48 | complicated queries and showing the highlighted results works best in 49 | a medium with more fidelity, such as the web. A [Rocket][] backend 50 | powers a [React][] and [Redux][] frontend. 51 | 52 | Rocket requires **nightly** Rust. 53 | 54 | [Rocket]: https://rocket.rs/ 55 | [React]: https://facebook.github.io/react/ 56 | [Redux]: http://redux.js.org/ 57 | 58 | ## Contribution opportunities 59 | 60 | A project always has need for help from interested people! 61 | 62 | ### Introductory opportunities 🌟 63 | 64 | These are things that anyone should be able to help with! 65 | 66 | - Suggest some queries that might be answerable given the structure of 67 | a Rust file. Ones that you have had in the Real World are preferred! 68 | - Try to run the indexer and server on your own files. 69 | 70 | ### Intermediate opportunities 🌟🌟🌟 71 | 72 | These might require diving into the code a bit and adding new code or 73 | changing existing code. 74 | 75 | - To be determined! 76 | 77 | Please open up an issue to begin a dialog before starting if a feature 78 | seems like it will require more than just a straight-forward addition! 79 | 80 | ### Advanced opportunities 🌟🌟🌟🌟🌟 81 | 82 | These are intense feature requests that probably require a good amount 83 | of effort and *definitely* should be discussed in an issue before 84 | beginning. 85 | 86 | - To be determined! 87 | 88 | ## License 89 | 90 | ebene-rust is distributed under the terms of both the MIT license and 91 | the Apache License (Version 2.0). 92 | 93 | ## Authors 94 | 95 | This crate was created by Jake Goulding of [Integer 32][]. 96 | 97 | [Integer 32]: http://www.integer32.com/ 98 | -------------------------------------------------------------------------------- /ui/app/reducer/structuredQuery.ts: -------------------------------------------------------------------------------- 1 | import { Kind, makeNothing, FlatQueryItems, isBinaryKind, FlatBinaryItem, isFlatBinaryItem } from 'app/types'; 2 | import { ActionType, Action } from 'app/actions'; 3 | 4 | import { initial, forTarget } from './higherOrder'; 5 | 6 | export type State = FlatQueryItems; 7 | 8 | export function rawReducer(state: State, action: Action): State { 9 | switch (action.type) { 10 | case ActionType.StructuredQueryKindUpdate: { 11 | const { kind, id } = action.payload; 12 | 13 | if (isBinaryKind(kind)) { 14 | const old = state[id]; 15 | 16 | if (isFlatBinaryItem(old)) { 17 | const { lhs, rhs } = old; 18 | const newx: FlatBinaryItem = { kind, lhs, rhs } as FlatBinaryItem; // xxx 19 | 20 | return { 21 | ...state, 22 | [id]: newx, 23 | } 24 | } else { 25 | // This isn't as efficient as it could be. Every time we 26 | // change to a binary type, we create brand new children 27 | // nodes and never recycle them. 28 | const lhs = Object.keys(state).length; 29 | const rhs = lhs + 1; 30 | const newx: FlatBinaryItem = { kind, lhs, rhs } as FlatBinaryItem; // xxx 31 | 32 | return { 33 | ...state, 34 | [id]: newx, 35 | [lhs]: makeNothing(), 36 | [rhs]: makeNothing(), 37 | } 38 | } 39 | } else if (kind === Kind.Layer) { 40 | return { 41 | ...state, 42 | [id]: { kind, name: '' } 43 | } 44 | } else if (kind === Kind.Nothing) { 45 | return { 46 | ...state, 47 | [id]: { kind } 48 | } 49 | } else if (kind === Kind.Term) { 50 | return { 51 | ...state, 52 | [id]: { kind, name: '', value: '' } 53 | } 54 | } 55 | 56 | const unreachable: never = kind; 57 | return unreachable; 58 | } 59 | case ActionType.LayerNameUpdate: { 60 | const { name, id } = action.payload; 61 | const old = state[id]; 62 | 63 | if (old.kind === Kind.Layer) { 64 | return { ...state, [id]: { ...old, name } }; 65 | } else { 66 | return state; 67 | } 68 | } 69 | case ActionType.TermNameUpdate: { 70 | const { name, id } = action.payload; 71 | const old = state[id]; 72 | 73 | if (old.kind === Kind.Term) { 74 | return { ...state, [id]: { ...old, name } }; 75 | } else { 76 | return state; 77 | } 78 | } 79 | case ActionType.TermValueUpdate: { 80 | const { value, id } = action.payload; 81 | const old = state[id]; 82 | 83 | if (old.kind === Kind.Term) { 84 | return { ...state, [id]: { ...old, value } }; 85 | } else { 86 | return state; 87 | } 88 | } 89 | default: 90 | return state; 91 | } 92 | } 93 | 94 | const initialStructuredQuery: State = { 95 | 0: { kind: Kind.Containing, lhs: 1, rhs: 2 }, 96 | 1: { kind: Kind.Layer, name: 'function' }, 97 | 2: { kind: Kind.Term, name: 'ident', value: 'pm' }, 98 | }; 99 | 100 | const targetedReducer = forTarget(rawReducer, 'query'); 101 | export default initial(targetedReducer, initialStructuredQuery); 102 | -------------------------------------------------------------------------------- /ui/app/types.ts: -------------------------------------------------------------------------------- 1 | export enum Kind { 2 | Nothing = 'Nothing', 3 | Layer = 'Layer', 4 | Term = 'Term', 5 | Containing = 'Containing', 6 | ContainedIn = 'ContainedIn', 7 | NotContaining = 'NotContaining', 8 | NotContainedIn = 'NotContainedIn', 9 | OneOf = 'OneOf', 10 | BothOf = 'BothOf', 11 | FollowedBy = 'FollowedBy', 12 | } 13 | 14 | export type BinaryKind = 15 | | Kind.BothOf 16 | | Kind.ContainedIn 17 | | Kind.Containing 18 | | Kind.FollowedBy 19 | | Kind.NotContainedIn 20 | | Kind.NotContaining 21 | | Kind.OneOf 22 | ; 23 | 24 | export function isBinaryKind(kind: Kind): kind is BinaryKind { 25 | switch (kind) { 26 | case Kind.Containing: 27 | case Kind.ContainedIn: 28 | case Kind.NotContaining: 29 | case Kind.NotContainedIn: 30 | case Kind.OneOf: 31 | case Kind.BothOf: 32 | case Kind.FollowedBy: 33 | return true; 34 | default: 35 | return false; 36 | } 37 | } 38 | 39 | // The flat query is stored in the state and is a flat mapping of ID number to data 40 | 41 | export type FlatQueryItem = 42 | | FlatTerm 43 | | FlatBinaryItem 44 | | FlatLayer 45 | | FlatNothing 46 | ; 47 | 48 | export type FlatBinaryItem = 49 | | FlatBinary 50 | | FlatBinary 51 | | FlatBinary 52 | | FlatBinary 53 | | FlatBinary 54 | | FlatBinary 55 | | FlatBinary 56 | ; 57 | 58 | export interface FlatBinary { 59 | kind: T, 60 | lhs: number, 61 | rhs: number, 62 | } 63 | 64 | export function isFlatBinaryItem(item: FlatQueryItem): item is FlatBinaryItem { 65 | return isBinaryKind(item.kind); 66 | } 67 | 68 | export interface FlatTerm { 69 | kind: Kind.Term, 70 | name: string, 71 | value: string, 72 | } 73 | 74 | export interface FlatLayer { 75 | kind: Kind.Layer, 76 | name: string, 77 | } 78 | 79 | export interface FlatNothing { 80 | kind: Kind.Nothing, 81 | } 82 | 83 | export const makeNothing: () => FlatNothing = () => ({ kind: Kind.Nothing }); 84 | 85 | export interface FlatQueryItems { 86 | [index: number]: FlatQueryItem; 87 | } 88 | 89 | // The tree query is used by the UI and reflects the recursive structure 90 | 91 | export type TreeQueryItem = 92 | | TreeTerm 93 | | TreeBinary 94 | | TreeBinary 95 | | TreeBinary 96 | | TreeBinary 97 | | TreeBinary 98 | | TreeBinary 99 | | TreeBinary 100 | | TreeLayer 101 | | TreeNothing; 102 | 103 | export interface TreeTerm { 104 | id: number, 105 | kind: Kind.Term, 106 | name: string, 107 | value: string, 108 | } 109 | 110 | export interface TreeBinary { 111 | id: number, 112 | kind: T, 113 | lhs: TreeQueryItem, 114 | rhs: TreeQueryItem, 115 | } 116 | 117 | export interface TreeLayer { 118 | id: number, 119 | kind: Kind.Layer, 120 | name: string, 121 | } 122 | 123 | export interface TreeNothing { 124 | id: number, 125 | kind: Kind.Nothing, 126 | } 127 | 128 | // The api query is used by the backend and reflects the recursive structure 129 | 130 | export type ApiQueryItem = 131 | | ApiTerm 132 | | ApiBinary 133 | | ApiBinary 134 | | ApiBinary 135 | | ApiBinary 136 | | ApiBinary 137 | | ApiBinary 138 | | ApiBinary 139 | | ApiLayer 140 | | ApiNothing; 141 | 142 | export interface ApiTerm { 143 | [Kind.Term]: { 144 | name: string, 145 | value: string, 146 | } 147 | } 148 | 149 | // https://stackoverflow.com/a/50849477/155423 150 | export type ApiBinary = { 151 | [k in K]: ApiQueryItem[]; 152 | } 153 | 154 | export interface ApiLayer { 155 | [Kind.Layer]: { 156 | name: string, 157 | } 158 | } 159 | 160 | export type ApiNothing = Kind.Nothing; 161 | 162 | export type Extents = [number, number][]; 163 | 164 | export interface QueryResult { 165 | text: string; 166 | highlights: Extents[]; 167 | } 168 | -------------------------------------------------------------------------------- /ui/app/actions.ts: -------------------------------------------------------------------------------- 1 | import { Kind, QueryResult } from './types'; 2 | 3 | export enum ActionType { 4 | AdvancedHighlightUpdate = 'ADVANCED_HIGHLIGHT_UPDATE', 5 | AvailableLayersUpdate = 'AVAILABLE_LAYERS_UPDATE', 6 | AvailableTermsUpdate = 'AVAILABLE_TERMS_UPDATE', 7 | AdvancedQueryUpdate = 'ADVANCED_QUERY_UPDATE', 8 | HighlightAdd = 'HIGHLIGHT_ADD', 9 | LayerNameUpdate = 'LAYER_NAME_UPDATE', 10 | QueryResults = 'QUERY_RESULTS', 11 | QueryToggle = 'QUERY_TOGGLE', 12 | StructuredQueryKindUpdate = 'STRUCTURED_QUERY_KIND_UPDATE', 13 | TermNameUpdate = 'TERM_NAME_UPDATE', 14 | TermValueUpdate = 'TERM_VALUE_UPDATE', 15 | } 16 | 17 | // The general shape of any possible Redux action. More complicated 18 | // than the upstream version to allow a specific type for the type 19 | // property. 20 | export interface FluxStandardAction { 21 | type: T; 22 | payload?: Payload; 23 | error?: boolean; 24 | meta?: Meta; 25 | } 26 | 27 | // Common variants of the action 28 | interface SuccessAction extends FluxStandardAction { 29 | error: undefined; 30 | } 31 | interface SuccessActionPayload extends FluxStandardAction { 32 | payload: P; 33 | error: undefined; 34 | } 35 | interface ErrorActionPayload extends FluxStandardAction { 36 | payload: P; 37 | error: true; 38 | } 39 | 40 | function createAction(type: T): SuccessAction 41 | function createAction(type: T, payload: P): SuccessActionPayload 42 | function createAction(type: T, payload?: P) { 43 | return payload === undefined ? { type } : { type, payload }; 44 | } 45 | 46 | function createActionError(type: T, payload: P): ErrorActionPayload { 47 | return { type, payload, error: true }; 48 | } 49 | 50 | export const toggleAdvanced = () => 51 | createAction(ActionType.QueryToggle); 52 | 53 | export const updateAdvancedQuery = (query: string) => 54 | createAction(ActionType.AdvancedQueryUpdate, { query }); 55 | 56 | export const updateAdvancedHighlight = (highlight: string) => 57 | createAction(ActionType.AdvancedHighlightUpdate, { highlight }); 58 | 59 | export const updateQueryResults = (results: QueryResult[]) => 60 | createAction(ActionType.QueryResults, { results }); 61 | 62 | export const queryFailed = (message: string) => 63 | createActionError(ActionType.QueryResults, new Error(message)); 64 | 65 | export const updateKind = (id: number, kind: Kind) => 66 | createAction(ActionType.StructuredQueryKindUpdate, { id, kind }); 67 | 68 | export const updateLayerName = (id: number, name: string) => 69 | createAction(ActionType.LayerNameUpdate, { id, name }); 70 | 71 | export const updateTermName = (id: number, name: string) => 72 | createAction(ActionType.TermNameUpdate, { id, name }); 73 | 74 | export const updateTermValue = (id: number, value: string) => 75 | createAction(ActionType.TermValueUpdate, { id, value }); 76 | 77 | export const highlightAdd = (index: number) => 78 | createAction(ActionType.HighlightAdd, { index }); 79 | 80 | export const updateAvailableLayers = (layers: string[]) => 81 | createAction(ActionType.AvailableLayersUpdate, { layers }); 82 | 83 | export const updateAvailableTerms = (terms: string[]) => 84 | createAction(ActionType.AvailableTermsUpdate, { terms }); 85 | 86 | export type Action = 87 | | ReturnType 88 | | ReturnType 89 | | ReturnType 90 | | ReturnType 91 | | ReturnType 92 | | ReturnType 93 | | ReturnType 94 | | ReturnType 95 | | ReturnType 96 | | ReturnType 97 | | ReturnType 98 | | ReturnType 99 | ; 100 | 101 | // Higher order action creator modifiers 102 | 103 | export interface WithTarget { 104 | meta: { 105 | target: string; 106 | } 107 | } 108 | 109 | export function withTarget>(action: (...args: any[]) => A, target: string) { 110 | return function(...args: any[]): A & WithTarget { 111 | let act = action(...args); 112 | let meta = Object.assign({}, act.meta, { target }); 113 | return Object.assign(act, { meta }); 114 | } 115 | } 116 | 117 | export function isWithTarget(a: any): a is WithTarget { 118 | return !!a['meta'] && typeof a['meta']['target'] == "string"; 119 | } 120 | 121 | export interface WithTargetIndex { 122 | meta: { 123 | targetIndex: number; 124 | } 125 | } 126 | 127 | export function withTargetIndex>(action: (...args: any[]) => A, index: number) { 128 | return function(...args: any[]): A & WithTargetIndex { 129 | let act = action(...args); 130 | let meta = Object.assign({}, act.meta, { targetIndex: index }); 131 | return Object.assign(act, { meta }); 132 | } 133 | } 134 | 135 | export function isWithTargetIndex(a: any): a is WithTargetIndex { 136 | return !!a['meta'] && typeof a['meta']['targetIndex'] == "number"; 137 | } 138 | -------------------------------------------------------------------------------- /src/bin/indexer.rs: -------------------------------------------------------------------------------- 1 | extern crate fuzzy_pickles; 2 | extern crate serde_json; 3 | #[macro_use] 4 | extern crate serde_derive; 5 | 6 | use std::fs::File; 7 | use std::env; 8 | use std::io::prelude::*; 9 | use std::collections::{BTreeMap, BTreeSet}; 10 | 11 | use fuzzy_pickles::{ast, visit::{Visit, Visitor, Control}, HasExtent}; 12 | 13 | #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)] 14 | struct Extent(usize, usize); 15 | 16 | impl From for Extent { 17 | fn from(other: fuzzy_pickles::Extent) -> Self { 18 | Extent(other.0, other.1) 19 | } 20 | } 21 | 22 | #[derive(Debug, Default)] 23 | struct Indexing { 24 | source: String, 25 | 26 | term_ident: BTreeMap>, 27 | 28 | layer_enum: BTreeSet, 29 | layer_function: BTreeSet, 30 | layer_function_header: BTreeSet, 31 | layer_struct: BTreeSet, 32 | layer_generic_declarations: BTreeSet, 33 | layer_where: BTreeSet, 34 | 35 | layers_expression: Vec>, 36 | layers_statement: Vec>, 37 | 38 | stmt_depth: usize, 39 | expr_depth: usize, 40 | } 41 | 42 | impl std::ops::Index for Indexing { 43 | type Output = str; 44 | 45 | fn index(&self, extent: fuzzy_pickles::Extent) -> &str { 46 | &self.source[extent.0..extent.1] 47 | } 48 | } 49 | 50 | impl Visitor<'_> for Indexing { 51 | fn visit_ident(&mut self, ident: &ast::Ident) -> Control { 52 | let s = self[ident.extent].to_owned(); 53 | self.term_ident.entry(s).or_insert_with(BTreeSet::new).insert(ident.extent.into()); 54 | Control::Continue 55 | } 56 | 57 | fn visit_function(&mut self, function: &ast::Function) -> Control { 58 | self.layer_function.insert(function.extent.into()); 59 | Control::Continue 60 | } 61 | 62 | fn visit_function_header(&mut self, header: &ast::FunctionHeader) -> Control { 63 | self.layer_function_header.insert(header.extent.into()); 64 | Control::Continue 65 | } 66 | 67 | fn visit_enum(&mut self, e: &ast::Enum) -> Control { 68 | self.layer_enum.insert(e.extent.into()); 69 | Control::Continue 70 | } 71 | 72 | fn visit_struct(&mut self, s: &ast::Struct) -> Control { 73 | self.layer_struct.insert(s.extent.into()); 74 | Control::Continue 75 | } 76 | 77 | fn visit_generic_declarations(&mut self, gd: &ast::GenericDeclarations) -> Control { 78 | self.layer_generic_declarations.insert(gd.extent.into()); 79 | Control::Continue 80 | } 81 | 82 | fn visit_where(&mut self, w: &ast::Where) -> Control { 83 | self.layer_where.insert(w.extent().into()); 84 | Control::Continue 85 | } 86 | 87 | fn visit_statement(&mut self, s: &ast::Statement) -> Control { 88 | while self.layers_statement.len() <= self.stmt_depth { 89 | self.layers_statement.push(BTreeSet::new()); 90 | } 91 | self.layers_statement[self.stmt_depth].insert(s.extent().into()); 92 | 93 | self.stmt_depth +=1; 94 | Control::Continue 95 | } 96 | 97 | fn exit_statement(&mut self, _: &ast::Statement) { 98 | self.stmt_depth -= 1; 99 | } 100 | 101 | fn visit_expression(&mut self, e: &ast::Expression) -> Control { 102 | while self.layers_expression.len() <= self.expr_depth { 103 | self.layers_expression.push(BTreeSet::new()); 104 | } 105 | self.layers_expression[self.expr_depth].insert(e.extent().into()); 106 | 107 | self.expr_depth += 1; 108 | Control::Continue 109 | } 110 | 111 | fn exit_expression(&mut self, _: &ast::Expression) { 112 | self.expr_depth -= 1; 113 | } 114 | } 115 | 116 | #[derive(Debug, Default, Serialize, Deserialize)] 117 | struct IndexedFile { 118 | source: String, 119 | layers: BTreeMap>, 120 | terms: BTreeMap>>, 121 | } 122 | 123 | // TODO: This was extracted from `ebene`; should be made public 124 | fn find_invalid_gc_list_pair(extents: &[Extent]) -> Option<(Extent, Extent)> { 125 | extents 126 | .windows(2) 127 | .map(|window| (window[0], window[1])) 128 | .find(|&(a, b)| b.0 <= a.0 || b.1 <= a.1) 129 | } 130 | 131 | impl IndexedFile { 132 | fn validate(&self) { 133 | for (layer_name, layer_extents) in &self.layers { 134 | let layer_extents: Vec<_> = layer_extents.iter().cloned().collect(); 135 | if let Some(bad) = find_invalid_gc_list_pair(&layer_extents) { 136 | println!("WARNING: Layer {} has invalid extents: {:?}", layer_name, bad); 137 | } 138 | } 139 | } 140 | } 141 | 142 | impl From for IndexedFile { 143 | fn from(other: Indexing) -> IndexedFile { 144 | let Indexing { 145 | source, 146 | 147 | term_ident, 148 | 149 | layer_enum, 150 | layer_function, 151 | layer_function_header, 152 | layer_struct, 153 | layer_generic_declarations, 154 | layer_where, 155 | 156 | layers_expression, 157 | layers_statement, 158 | 159 | .. 160 | } = other; 161 | 162 | let mut layers = BTreeMap::new(); 163 | layers.insert("enum".into(), layer_enum); 164 | layers.insert("function".into(), layer_function); 165 | layers.insert("function-header".into(), layer_function_header); 166 | layers.insert("struct".into(), layer_struct); 167 | layers.insert("generic-declarations".into(), layer_generic_declarations); 168 | layers.insert("where".into(), layer_where); 169 | 170 | for (i, layer) in layers_expression.into_iter().enumerate() { 171 | layers.insert(format!("expression-{}", i), layer); 172 | } 173 | for (i, layer) in layers_statement.into_iter().enumerate() { 174 | layers.insert(format!("statement-{}", i), layer); 175 | } 176 | 177 | let mut terms = BTreeMap::new(); 178 | terms.insert("ident".into(), term_ident); 179 | 180 | IndexedFile { source, terms, layers } 181 | } 182 | } 183 | 184 | fn main() { 185 | let fname = env::args().nth(1).expect("Need filename argument"); 186 | let mut f = File::open(fname).expect("Can't open"); 187 | let mut s = String::new(); 188 | f.read_to_string(&mut s).expect("Can't read"); 189 | 190 | let file = match fuzzy_pickles::parse_rust_file(&s) { 191 | Ok(file) => file, 192 | Err(detail) => { 193 | panic!("{}", detail.with_text(&s)); 194 | } 195 | }; 196 | 197 | let mut d = Indexing::default(); 198 | d.source = s; 199 | 200 | file.visit(&mut d); 201 | 202 | let d: IndexedFile = d.into(); 203 | d.validate(); 204 | 205 | let mut out = std::io::stdout(); 206 | serde_json::ser::to_writer(&mut out, &d).expect("Nope"); 207 | } 208 | 209 | // Goal: 210 | // What methods take a generic argument that implements a trait `Foo` 211 | -------------------------------------------------------------------------------- /src/bin/server.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | extern crate ebene; 4 | 5 | extern crate serde; 6 | extern crate serde_json; 7 | #[macro_use] 8 | extern crate serde_derive; 9 | 10 | #[macro_use] 11 | extern crate lazy_static; 12 | 13 | #[macro_use] 14 | extern crate rocket; 15 | extern crate rocket_contrib; 16 | 17 | #[macro_use] 18 | extern crate quick_error; 19 | 20 | use std::fs::File; 21 | use std::borrow::Cow; 22 | use std::collections::BTreeMap; 23 | 24 | use ebene::{Algebra, ValidExtent}; 25 | 26 | use rocket::http::RawStr; 27 | use rocket_contrib::json::Json; 28 | 29 | use quick_error::ResultExt; 30 | 31 | quick_error! { 32 | #[derive(Debug, Clone, PartialEq)] 33 | enum Error { 34 | UnknownLayer(name: String) 35 | UnknownTerm(name: String) 36 | } 37 | } 38 | 39 | lazy_static! { 40 | static ref INDEX: Indexed = { 41 | let f = File::open("self.json").expect("no open file"); 42 | serde_json::de::from_reader(f).expect("no parse") 43 | }; 44 | } 45 | 46 | const IDENT_TERM_NAME: &'static str = "ident"; 47 | 48 | // This struct has mismatched "extent" types with the indexer... 49 | #[derive(Debug, Default, Serialize, Deserialize)] 50 | struct Indexed { 51 | source: String, 52 | layers: BTreeMap>, 53 | terms: BTreeMap>>, 54 | } 55 | 56 | impl Indexed { 57 | fn layer_for(&self, name: &str) -> Option<&[ebene::ValidExtent]> { 58 | self.layers.get(name).map(Vec::as_slice) 59 | } 60 | 61 | fn term_for(&self, name: &str, value: &str) -> Option<&[ebene::ValidExtent]> { 62 | self.terms.get(name) 63 | .map(|x| { 64 | x.get(value).map_or(&[][..], Vec::as_slice) 65 | }) 66 | } 67 | } 68 | 69 | impl std::ops::Index for Indexed { 70 | type Output = str; 71 | 72 | fn index(&self, extent: ValidExtent) -> &str { 73 | &self.source[(extent.0 as usize)..(extent.1 as usize)] 74 | } 75 | } 76 | 77 | fn compile(q: StructuredQuery) -> Result, Error> { 78 | match q { 79 | StructuredQuery::Nothing => { 80 | Ok(Box::new(ebene::Empty)) 81 | } 82 | StructuredQuery::Containing(lhs, rhs) => { 83 | let lhs = compile(*lhs)?; 84 | let rhs = compile(*rhs)?; 85 | Ok(Box::new(ebene::Containing::new(lhs, rhs))) 86 | } 87 | StructuredQuery::ContainedIn(lhs, rhs) => { 88 | let lhs = compile(*lhs)?; 89 | let rhs = compile(*rhs)?; 90 | Ok(Box::new(ebene::ContainedIn::new(lhs, rhs))) 91 | } 92 | StructuredQuery::NotContaining(lhs, rhs) => { 93 | let lhs = compile(*lhs)?; 94 | let rhs = compile(*rhs)?; 95 | Ok(Box::new(ebene::NotContaining::new(lhs, rhs))) 96 | } 97 | StructuredQuery::NotContainedIn(lhs, rhs) => { 98 | let lhs = compile(*lhs)?; 99 | let rhs = compile(*rhs)?; 100 | Ok(Box::new(ebene::NotContainedIn::new(lhs, rhs))) 101 | } 102 | StructuredQuery::BothOf(lhs, rhs) => { 103 | let lhs = compile(*lhs)?; 104 | let rhs = compile(*rhs)?; 105 | Ok(Box::new(ebene::BothOf::new(lhs, rhs))) 106 | } 107 | StructuredQuery::OneOf(lhs, rhs) => { 108 | let lhs = compile(*lhs)?; 109 | let rhs = compile(*rhs)?; 110 | Ok(Box::new(ebene::OneOf::new(lhs, rhs))) 111 | } 112 | StructuredQuery::FollowedBy(lhs, rhs) => { 113 | let lhs = compile(*lhs)?; 114 | let rhs = compile(*rhs)?; 115 | Ok(Box::new(ebene::FollowedBy::new(lhs, rhs))) 116 | } 117 | StructuredQuery::Layer { name } => { 118 | INDEX.layer_for(&name) 119 | .map(|e| Box::new(e) as Box) 120 | .ok_or_else(|| Error::UnknownLayer(name)) 121 | } 122 | StructuredQuery::Term { name, value } => { 123 | INDEX.term_for(&name, &value) 124 | .map(|e| Box::new(e) as Box) 125 | .ok_or_else(|| Error::UnknownTerm(name)) 126 | } 127 | } 128 | } 129 | 130 | #[get("/dev/source")] 131 | fn dev_source() -> Json { 132 | Json(INDEX.source.clone()) 133 | } 134 | 135 | #[get("/dev/layers")] 136 | fn dev_layers() -> Json> { 137 | Json(INDEX.layers.keys().map(Clone::clone).collect()) 138 | } 139 | 140 | #[get("/dev/layers/")] 141 | fn dev_layer(layer: String) -> Option>> { 142 | INDEX.layers.get(&layer).map(|l| Json(l.to_owned())) 143 | } 144 | 145 | #[get("/dev/terms")] 146 | fn dev_terms() -> Json> { 147 | Json(INDEX.terms.keys().map(Clone::clone).collect()) 148 | } 149 | 150 | #[get("/dev/terms/")] 151 | fn dev_terms_kinds(kind: String) -> Option>> { 152 | INDEX.terms.get(&kind) 153 | .map(|k| Json(k.keys().map(Clone::clone).collect())) 154 | } 155 | 156 | #[get("/dev/terms//")] 157 | fn dev_terms_kind(kind: String, term: String) -> Option>> { 158 | INDEX.terms.get(&kind) 159 | .and_then(|k| k.get(&term)) 160 | .map(|t| Json(t.to_owned())) 161 | } 162 | 163 | quick_error! { 164 | #[derive(Debug)] 165 | enum JsonStringError { 166 | NotUtf8(err: std::str::Utf8Error, val: String) { 167 | context(val: &'a RawStr, err: std::str::Utf8Error) -> (err, val.as_str().into()) 168 | } 169 | NotDecodable(err: serde_json::Error, val: String) { 170 | context(val: Cow<'a, str>, err: serde_json::Error) -> (err, val.into()) 171 | } 172 | } 173 | } 174 | 175 | #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 176 | struct JsonString(T); 177 | 178 | impl<'v, T> rocket::request::FromFormValue<'v> for JsonString 179 | where T: serde::de::DeserializeOwned, 180 | { 181 | type Error = JsonStringError; 182 | 183 | fn from_form_value(form_value: &'v RawStr) -> Result { 184 | let form_value = form_value.percent_decode().context(form_value)?; 185 | let form_value = serde_json::from_str(&form_value).context(form_value)?; 186 | Ok(JsonString(form_value)) 187 | } 188 | } 189 | 190 | #[derive(Debug, Serialize, Deserialize)] 191 | enum StructuredQuery { 192 | Nothing, 193 | Containing(Box, Box), 194 | ContainedIn(Box, Box), 195 | NotContaining(Box, Box), 196 | NotContainedIn(Box, Box), 197 | BothOf(Box, Box), 198 | OneOf(Box, Box), 199 | FollowedBy(Box, Box), 200 | Layer { name: String }, 201 | Term { name: String, value: String }, 202 | } 203 | 204 | #[derive(Debug, Default, Serialize)] 205 | struct SearchResults { 206 | results: Vec, 207 | } 208 | 209 | #[derive(Debug, Serialize)] 210 | struct SearchResult { 211 | text: String, 212 | highlights: Vec>, 213 | } 214 | 215 | fn offset_backwards(extent: ValidExtent, offset: u64) -> ValidExtent { 216 | (extent.0 - offset, extent.1 - offset) 217 | } 218 | 219 | #[get("/search?&")] 220 | fn search(q: Option>, h: Option>>) -> Json { 221 | println!("Query: {:?}", q); 222 | println!("Highlight: {:?}", h); 223 | 224 | let q = match q { 225 | Some(q) => q.0, 226 | None => return Json(SearchResults::default()), 227 | }; 228 | 229 | let container_query = compile(q).expect("can't compile query"); 230 | let highlights = h.map_or_else(Vec::new, |h| h.0); 231 | let highlight_queries: Result, _> = highlights.into_iter().map(compile).collect(); 232 | let highlight_queries = highlight_queries.expect("Can't compile highlights"); 233 | 234 | let results = container_query.iter_tau().map(|container_extent| { 235 | let container_text = &INDEX[container_extent]; 236 | 237 | let highlights_extents = highlight_queries.iter().map(|highlight_query| { 238 | let container_extent_range = &[container_extent][..]; // TODO: impl Algebra for (u64, u64)?; 239 | 240 | let this_result_highlights = ebene::ContainedIn::new(highlight_query, container_extent_range); 241 | 242 | this_result_highlights.iter_tau().map(|ex| { 243 | offset_backwards(ex, container_extent.0) 244 | }).collect() 245 | }).collect(); 246 | 247 | SearchResult { text: container_text.to_owned(), highlights: highlights_extents } 248 | }).collect(); 249 | 250 | Json(SearchResults { results }) 251 | } 252 | 253 | fn main() { 254 | println!("Indexed {:?} idents", INDEX.terms.get(IDENT_TERM_NAME).map(|s| s.len())); 255 | rocket::ignite().mount("/", routes![dev_source, dev_layers, dev_layer, dev_terms, dev_terms_kinds, dev_terms_kind, search]).launch(); 256 | } 257 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2017 Jake Goulding 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aead" 7 | version = "0.3.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" 10 | dependencies = [ 11 | "generic-array", 12 | ] 13 | 14 | [[package]] 15 | name = "aes" 16 | version = "0.6.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" 19 | dependencies = [ 20 | "aes-soft", 21 | "aesni", 22 | "cipher", 23 | ] 24 | 25 | [[package]] 26 | name = "aes-gcm" 27 | version = "0.8.0" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" 30 | dependencies = [ 31 | "aead", 32 | "aes", 33 | "cipher", 34 | "ctr", 35 | "ghash", 36 | "subtle", 37 | ] 38 | 39 | [[package]] 40 | name = "aes-soft" 41 | version = "0.6.4" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" 44 | dependencies = [ 45 | "cipher", 46 | "opaque-debug", 47 | ] 48 | 49 | [[package]] 50 | name = "aesni" 51 | version = "0.10.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" 54 | dependencies = [ 55 | "cipher", 56 | "opaque-debug", 57 | ] 58 | 59 | [[package]] 60 | name = "atty" 61 | version = "0.2.14" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 64 | dependencies = [ 65 | "hermit-abi 0.1.19", 66 | "libc", 67 | "winapi 0.3.9", 68 | ] 69 | 70 | [[package]] 71 | name = "autocfg" 72 | version = "1.1.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 75 | 76 | [[package]] 77 | name = "base64" 78 | version = "0.9.3" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" 81 | dependencies = [ 82 | "byteorder", 83 | "safemem", 84 | ] 85 | 86 | [[package]] 87 | name = "base64" 88 | version = "0.13.1" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 91 | 92 | [[package]] 93 | name = "bitflags" 94 | version = "1.3.2" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 97 | 98 | [[package]] 99 | name = "block-buffer" 100 | version = "0.9.0" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 103 | dependencies = [ 104 | "generic-array", 105 | ] 106 | 107 | [[package]] 108 | name = "byteorder" 109 | version = "1.4.3" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 112 | 113 | [[package]] 114 | name = "cfg-if" 115 | version = "0.1.10" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 118 | 119 | [[package]] 120 | name = "cfg-if" 121 | version = "1.0.0" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 124 | 125 | [[package]] 126 | name = "cipher" 127 | version = "0.2.5" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" 130 | dependencies = [ 131 | "generic-array", 132 | ] 133 | 134 | [[package]] 135 | name = "cookie" 136 | version = "0.11.5" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "be2018768ed1d848cc4d347d551546474025ba820e5db70e4c9aaa349f678bd7" 139 | dependencies = [ 140 | "aes-gcm", 141 | "base64 0.13.1", 142 | "hkdf", 143 | "hmac", 144 | "percent-encoding 2.3.0", 145 | "rand", 146 | "sha2", 147 | "time", 148 | ] 149 | 150 | [[package]] 151 | name = "cpufeatures" 152 | version = "0.2.9" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" 155 | dependencies = [ 156 | "libc", 157 | ] 158 | 159 | [[package]] 160 | name = "cpuid-bool" 161 | version = "0.2.0" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" 164 | 165 | [[package]] 166 | name = "crypto-mac" 167 | version = "0.10.1" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" 170 | dependencies = [ 171 | "generic-array", 172 | "subtle", 173 | ] 174 | 175 | [[package]] 176 | name = "ctr" 177 | version = "0.6.0" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" 180 | dependencies = [ 181 | "cipher", 182 | ] 183 | 184 | [[package]] 185 | name = "devise" 186 | version = "0.2.1" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "dd716c4a507adc5a2aa7c2a372d06c7497727e0892b243d3036bc7478a13e526" 189 | dependencies = [ 190 | "devise_codegen", 191 | "devise_core", 192 | ] 193 | 194 | [[package]] 195 | name = "devise_codegen" 196 | version = "0.2.1" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "ea7b8290d118127c08e3669da20b331bed56b09f20be5945b7da6c116d8fab53" 199 | dependencies = [ 200 | "devise_core", 201 | "quote 0.6.13", 202 | ] 203 | 204 | [[package]] 205 | name = "devise_core" 206 | version = "0.2.1" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "d1053e9d5d5aade9bcedb5ab53b78df2b56ff9408a3138ce77eaaef87f932373" 209 | dependencies = [ 210 | "bitflags", 211 | "proc-macro2 0.4.30", 212 | "quote 0.6.13", 213 | "syn 0.15.44", 214 | ] 215 | 216 | [[package]] 217 | name = "digest" 218 | version = "0.9.0" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 221 | dependencies = [ 222 | "generic-array", 223 | ] 224 | 225 | [[package]] 226 | name = "ebene" 227 | version = "0.2.0" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "897a0b00c2041b378d5d1f58bc4fcf77c7f4196956f859c42dc72e830b66e00b" 230 | 231 | [[package]] 232 | name = "ebene_rs" 233 | version = "0.1.0" 234 | dependencies = [ 235 | "ebene", 236 | "fuzzy-pickles", 237 | "lazy_static", 238 | "quick-error", 239 | "rocket", 240 | "rocket_codegen", 241 | "rocket_contrib", 242 | "serde", 243 | "serde_derive", 244 | "serde_json", 245 | ] 246 | 247 | [[package]] 248 | name = "filetime" 249 | version = "0.2.22" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" 252 | dependencies = [ 253 | "cfg-if 1.0.0", 254 | "libc", 255 | "redox_syscall", 256 | "windows-sys", 257 | ] 258 | 259 | [[package]] 260 | name = "fsevent" 261 | version = "0.4.0" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" 264 | dependencies = [ 265 | "bitflags", 266 | "fsevent-sys", 267 | ] 268 | 269 | [[package]] 270 | name = "fsevent-sys" 271 | version = "2.0.1" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" 274 | dependencies = [ 275 | "libc", 276 | ] 277 | 278 | [[package]] 279 | name = "fuchsia-zircon" 280 | version = "0.3.3" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 283 | dependencies = [ 284 | "bitflags", 285 | "fuchsia-zircon-sys", 286 | ] 287 | 288 | [[package]] 289 | name = "fuchsia-zircon-sys" 290 | version = "0.3.3" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 293 | 294 | [[package]] 295 | name = "fuzzy-pickles" 296 | version = "0.1.1" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "c64314dfe37c3db6fe01915b6c24fa7f4fdfe1cb9e0a10963482f494818c1706" 299 | dependencies = [ 300 | "fuzzy-pickles-derive", 301 | "peresil", 302 | "unicode-xid 0.2.4", 303 | ] 304 | 305 | [[package]] 306 | name = "fuzzy-pickles-derive" 307 | version = "0.1.1" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "4479677dc8b776f0196348bd001c23aeebd9a1295f95309f123429da94807fd5" 310 | dependencies = [ 311 | "proc-macro2 1.0.66", 312 | "quote 1.0.33", 313 | "syn 1.0.109", 314 | ] 315 | 316 | [[package]] 317 | name = "generic-array" 318 | version = "0.14.7" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 321 | dependencies = [ 322 | "typenum", 323 | "version_check 0.9.4", 324 | ] 325 | 326 | [[package]] 327 | name = "getrandom" 328 | version = "0.2.10" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 331 | dependencies = [ 332 | "cfg-if 1.0.0", 333 | "libc", 334 | "wasi 0.11.0+wasi-snapshot-preview1", 335 | ] 336 | 337 | [[package]] 338 | name = "ghash" 339 | version = "0.3.1" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" 342 | dependencies = [ 343 | "opaque-debug", 344 | "polyval", 345 | ] 346 | 347 | [[package]] 348 | name = "glob" 349 | version = "0.3.1" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 352 | 353 | [[package]] 354 | name = "hashbrown" 355 | version = "0.12.3" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 358 | 359 | [[package]] 360 | name = "hermit-abi" 361 | version = "0.1.19" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 364 | dependencies = [ 365 | "libc", 366 | ] 367 | 368 | [[package]] 369 | name = "hermit-abi" 370 | version = "0.3.2" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 373 | 374 | [[package]] 375 | name = "hkdf" 376 | version = "0.10.0" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" 379 | dependencies = [ 380 | "digest", 381 | "hmac", 382 | ] 383 | 384 | [[package]] 385 | name = "hmac" 386 | version = "0.10.1" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" 389 | dependencies = [ 390 | "crypto-mac", 391 | "digest", 392 | ] 393 | 394 | [[package]] 395 | name = "httparse" 396 | version = "1.8.0" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 399 | 400 | [[package]] 401 | name = "hyper" 402 | version = "0.10.16" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" 405 | dependencies = [ 406 | "base64 0.9.3", 407 | "httparse", 408 | "language-tags", 409 | "log 0.3.9", 410 | "mime", 411 | "num_cpus", 412 | "time", 413 | "traitobject", 414 | "typeable", 415 | "unicase", 416 | "url", 417 | ] 418 | 419 | [[package]] 420 | name = "idna" 421 | version = "0.1.5" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" 424 | dependencies = [ 425 | "matches", 426 | "unicode-bidi", 427 | "unicode-normalization", 428 | ] 429 | 430 | [[package]] 431 | name = "indexmap" 432 | version = "1.9.3" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 435 | dependencies = [ 436 | "autocfg", 437 | "hashbrown", 438 | ] 439 | 440 | [[package]] 441 | name = "inotify" 442 | version = "0.7.1" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" 445 | dependencies = [ 446 | "bitflags", 447 | "inotify-sys", 448 | "libc", 449 | ] 450 | 451 | [[package]] 452 | name = "inotify-sys" 453 | version = "0.1.5" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" 456 | dependencies = [ 457 | "libc", 458 | ] 459 | 460 | [[package]] 461 | name = "iovec" 462 | version = "0.1.4" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 465 | dependencies = [ 466 | "libc", 467 | ] 468 | 469 | [[package]] 470 | name = "itoa" 471 | version = "1.0.9" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 474 | 475 | [[package]] 476 | name = "kernel32-sys" 477 | version = "0.2.2" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 480 | dependencies = [ 481 | "winapi 0.2.8", 482 | "winapi-build", 483 | ] 484 | 485 | [[package]] 486 | name = "language-tags" 487 | version = "0.2.2" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" 490 | 491 | [[package]] 492 | name = "lazy_static" 493 | version = "1.4.0" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 496 | 497 | [[package]] 498 | name = "lazycell" 499 | version = "1.3.0" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 502 | 503 | [[package]] 504 | name = "libc" 505 | version = "0.2.147" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 508 | 509 | [[package]] 510 | name = "log" 511 | version = "0.3.9" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" 514 | dependencies = [ 515 | "log 0.4.20", 516 | ] 517 | 518 | [[package]] 519 | name = "log" 520 | version = "0.4.20" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 523 | 524 | [[package]] 525 | name = "matches" 526 | version = "0.1.10" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" 529 | 530 | [[package]] 531 | name = "memchr" 532 | version = "2.6.2" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" 535 | 536 | [[package]] 537 | name = "mime" 538 | version = "0.2.6" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" 541 | dependencies = [ 542 | "log 0.3.9", 543 | ] 544 | 545 | [[package]] 546 | name = "mio" 547 | version = "0.6.23" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" 550 | dependencies = [ 551 | "cfg-if 0.1.10", 552 | "fuchsia-zircon", 553 | "fuchsia-zircon-sys", 554 | "iovec", 555 | "kernel32-sys", 556 | "libc", 557 | "log 0.4.20", 558 | "miow", 559 | "net2", 560 | "slab", 561 | "winapi 0.2.8", 562 | ] 563 | 564 | [[package]] 565 | name = "mio-extras" 566 | version = "2.0.6" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" 569 | dependencies = [ 570 | "lazycell", 571 | "log 0.4.20", 572 | "mio", 573 | "slab", 574 | ] 575 | 576 | [[package]] 577 | name = "miow" 578 | version = "0.2.2" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" 581 | dependencies = [ 582 | "kernel32-sys", 583 | "net2", 584 | "winapi 0.2.8", 585 | "ws2_32-sys", 586 | ] 587 | 588 | [[package]] 589 | name = "net2" 590 | version = "0.2.39" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" 593 | dependencies = [ 594 | "cfg-if 0.1.10", 595 | "libc", 596 | "winapi 0.3.9", 597 | ] 598 | 599 | [[package]] 600 | name = "notify" 601 | version = "4.0.17" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" 604 | dependencies = [ 605 | "bitflags", 606 | "filetime", 607 | "fsevent", 608 | "fsevent-sys", 609 | "inotify", 610 | "libc", 611 | "mio", 612 | "mio-extras", 613 | "walkdir", 614 | "winapi 0.3.9", 615 | ] 616 | 617 | [[package]] 618 | name = "num_cpus" 619 | version = "1.16.0" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 622 | dependencies = [ 623 | "hermit-abi 0.3.2", 624 | "libc", 625 | ] 626 | 627 | [[package]] 628 | name = "opaque-debug" 629 | version = "0.3.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 632 | 633 | [[package]] 634 | name = "pear" 635 | version = "0.1.5" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "32dfa7458144c6af7f9ce6a137ef975466aa68ffa44d4d816ee5934018ba960a" 638 | dependencies = [ 639 | "pear_codegen", 640 | ] 641 | 642 | [[package]] 643 | name = "pear_codegen" 644 | version = "0.1.5" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "c0288ba5d581afbc93e2bbd931c1013584c15ecf46b1cdb927edc7abddbc8ca6" 647 | dependencies = [ 648 | "proc-macro2 0.4.30", 649 | "quote 0.6.13", 650 | "syn 0.15.44", 651 | "version_check 0.9.4", 652 | "yansi", 653 | ] 654 | 655 | [[package]] 656 | name = "percent-encoding" 657 | version = "1.0.1" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" 660 | 661 | [[package]] 662 | name = "percent-encoding" 663 | version = "2.3.0" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 666 | 667 | [[package]] 668 | name = "peresil" 669 | version = "0.4.0-alpha.0" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "596fbbf6b147b7f1511c5bbab949e1fc3805030e68f294adb89daae07a63faa5" 672 | 673 | [[package]] 674 | name = "polyval" 675 | version = "0.4.5" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" 678 | dependencies = [ 679 | "cpuid-bool", 680 | "opaque-debug", 681 | "universal-hash", 682 | ] 683 | 684 | [[package]] 685 | name = "ppv-lite86" 686 | version = "0.2.17" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 689 | 690 | [[package]] 691 | name = "proc-macro2" 692 | version = "0.4.30" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 695 | dependencies = [ 696 | "unicode-xid 0.1.0", 697 | ] 698 | 699 | [[package]] 700 | name = "proc-macro2" 701 | version = "1.0.66" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" 704 | dependencies = [ 705 | "unicode-ident", 706 | ] 707 | 708 | [[package]] 709 | name = "quick-error" 710 | version = "1.2.3" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 713 | 714 | [[package]] 715 | name = "quote" 716 | version = "0.6.13" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 719 | dependencies = [ 720 | "proc-macro2 0.4.30", 721 | ] 722 | 723 | [[package]] 724 | name = "quote" 725 | version = "1.0.33" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 728 | dependencies = [ 729 | "proc-macro2 1.0.66", 730 | ] 731 | 732 | [[package]] 733 | name = "rand" 734 | version = "0.8.5" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 737 | dependencies = [ 738 | "libc", 739 | "rand_chacha", 740 | "rand_core", 741 | ] 742 | 743 | [[package]] 744 | name = "rand_chacha" 745 | version = "0.3.1" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 748 | dependencies = [ 749 | "ppv-lite86", 750 | "rand_core", 751 | ] 752 | 753 | [[package]] 754 | name = "rand_core" 755 | version = "0.6.4" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 758 | dependencies = [ 759 | "getrandom", 760 | ] 761 | 762 | [[package]] 763 | name = "redox_syscall" 764 | version = "0.3.5" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 767 | dependencies = [ 768 | "bitflags", 769 | ] 770 | 771 | [[package]] 772 | name = "rocket" 773 | version = "0.4.11" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "83b9d9dc08c5dcc1d8126a9dd615545e6a358f8c13c883c8dfed8c0376fa355e" 776 | dependencies = [ 777 | "atty", 778 | "base64 0.13.1", 779 | "log 0.4.20", 780 | "memchr", 781 | "num_cpus", 782 | "pear", 783 | "rocket_codegen", 784 | "rocket_http", 785 | "state", 786 | "time", 787 | "toml", 788 | "version_check 0.9.4", 789 | "yansi", 790 | ] 791 | 792 | [[package]] 793 | name = "rocket_codegen" 794 | version = "0.4.11" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "2810037b5820098af97bd4fdd309e76a8101ceb178147de775c835a2537284fe" 797 | dependencies = [ 798 | "devise", 799 | "glob", 800 | "indexmap", 801 | "quote 0.6.13", 802 | "rocket_http", 803 | "version_check 0.9.4", 804 | "yansi", 805 | ] 806 | 807 | [[package]] 808 | name = "rocket_contrib" 809 | version = "0.4.11" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "e20efbc6a211cb3df5375accf532d4186f224b623f39eca650b19b96240c596b" 812 | dependencies = [ 813 | "log 0.4.20", 814 | "notify", 815 | "rocket", 816 | "serde", 817 | "serde_json", 818 | ] 819 | 820 | [[package]] 821 | name = "rocket_http" 822 | version = "0.4.11" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "2bf9cbd128e1f321a2d0bebd2b7cf0aafd89ca43edf69e49b56a5c46e48eb19f" 825 | dependencies = [ 826 | "cookie", 827 | "hyper", 828 | "indexmap", 829 | "pear", 830 | "percent-encoding 1.0.1", 831 | "smallvec", 832 | "state", 833 | "time", 834 | "unicode-xid 0.1.0", 835 | ] 836 | 837 | [[package]] 838 | name = "ryu" 839 | version = "1.0.15" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 842 | 843 | [[package]] 844 | name = "safemem" 845 | version = "0.3.3" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" 848 | 849 | [[package]] 850 | name = "same-file" 851 | version = "1.0.6" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 854 | dependencies = [ 855 | "winapi-util", 856 | ] 857 | 858 | [[package]] 859 | name = "serde" 860 | version = "1.0.188" 861 | source = "registry+https://github.com/rust-lang/crates.io-index" 862 | checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" 863 | dependencies = [ 864 | "serde_derive", 865 | ] 866 | 867 | [[package]] 868 | name = "serde_derive" 869 | version = "1.0.188" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" 872 | dependencies = [ 873 | "proc-macro2 1.0.66", 874 | "quote 1.0.33", 875 | "syn 2.0.29", 876 | ] 877 | 878 | [[package]] 879 | name = "serde_json" 880 | version = "1.0.105" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" 883 | dependencies = [ 884 | "itoa", 885 | "ryu", 886 | "serde", 887 | ] 888 | 889 | [[package]] 890 | name = "sha2" 891 | version = "0.9.9" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 894 | dependencies = [ 895 | "block-buffer", 896 | "cfg-if 1.0.0", 897 | "cpufeatures", 898 | "digest", 899 | "opaque-debug", 900 | ] 901 | 902 | [[package]] 903 | name = "slab" 904 | version = "0.4.9" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 907 | dependencies = [ 908 | "autocfg", 909 | ] 910 | 911 | [[package]] 912 | name = "smallvec" 913 | version = "1.11.0" 914 | source = "registry+https://github.com/rust-lang/crates.io-index" 915 | checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" 916 | 917 | [[package]] 918 | name = "state" 919 | version = "0.4.2" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483" 922 | 923 | [[package]] 924 | name = "subtle" 925 | version = "2.4.1" 926 | source = "registry+https://github.com/rust-lang/crates.io-index" 927 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 928 | 929 | [[package]] 930 | name = "syn" 931 | version = "0.15.44" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" 934 | dependencies = [ 935 | "proc-macro2 0.4.30", 936 | "quote 0.6.13", 937 | "unicode-xid 0.1.0", 938 | ] 939 | 940 | [[package]] 941 | name = "syn" 942 | version = "1.0.109" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 945 | dependencies = [ 946 | "proc-macro2 1.0.66", 947 | "quote 1.0.33", 948 | "unicode-ident", 949 | ] 950 | 951 | [[package]] 952 | name = "syn" 953 | version = "2.0.29" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" 956 | dependencies = [ 957 | "proc-macro2 1.0.66", 958 | "quote 1.0.33", 959 | "unicode-ident", 960 | ] 961 | 962 | [[package]] 963 | name = "time" 964 | version = "0.1.45" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" 967 | dependencies = [ 968 | "libc", 969 | "wasi 0.10.0+wasi-snapshot-preview1", 970 | "winapi 0.3.9", 971 | ] 972 | 973 | [[package]] 974 | name = "tinyvec" 975 | version = "1.6.0" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 978 | dependencies = [ 979 | "tinyvec_macros", 980 | ] 981 | 982 | [[package]] 983 | name = "tinyvec_macros" 984 | version = "0.1.1" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 987 | 988 | [[package]] 989 | name = "toml" 990 | version = "0.4.10" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" 993 | dependencies = [ 994 | "serde", 995 | ] 996 | 997 | [[package]] 998 | name = "traitobject" 999 | version = "0.1.0" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" 1002 | 1003 | [[package]] 1004 | name = "typeable" 1005 | version = "0.1.2" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" 1008 | 1009 | [[package]] 1010 | name = "typenum" 1011 | version = "1.16.0" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 1014 | 1015 | [[package]] 1016 | name = "unicase" 1017 | version = "1.4.2" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" 1020 | dependencies = [ 1021 | "version_check 0.1.5", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "unicode-bidi" 1026 | version = "0.3.13" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 1029 | 1030 | [[package]] 1031 | name = "unicode-ident" 1032 | version = "1.0.11" 1033 | source = "registry+https://github.com/rust-lang/crates.io-index" 1034 | checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" 1035 | 1036 | [[package]] 1037 | name = "unicode-normalization" 1038 | version = "0.1.22" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1041 | dependencies = [ 1042 | "tinyvec", 1043 | ] 1044 | 1045 | [[package]] 1046 | name = "unicode-xid" 1047 | version = "0.1.0" 1048 | source = "registry+https://github.com/rust-lang/crates.io-index" 1049 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1050 | 1051 | [[package]] 1052 | name = "unicode-xid" 1053 | version = "0.2.4" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" 1056 | 1057 | [[package]] 1058 | name = "universal-hash" 1059 | version = "0.4.1" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" 1062 | dependencies = [ 1063 | "generic-array", 1064 | "subtle", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "url" 1069 | version = "1.7.2" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" 1072 | dependencies = [ 1073 | "idna", 1074 | "matches", 1075 | "percent-encoding 1.0.1", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "version_check" 1080 | version = "0.1.5" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" 1083 | 1084 | [[package]] 1085 | name = "version_check" 1086 | version = "0.9.4" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1089 | 1090 | [[package]] 1091 | name = "walkdir" 1092 | version = "2.3.3" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" 1095 | dependencies = [ 1096 | "same-file", 1097 | "winapi-util", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "wasi" 1102 | version = "0.10.0+wasi-snapshot-preview1" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1105 | 1106 | [[package]] 1107 | name = "wasi" 1108 | version = "0.11.0+wasi-snapshot-preview1" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1111 | 1112 | [[package]] 1113 | name = "winapi" 1114 | version = "0.2.8" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1117 | 1118 | [[package]] 1119 | name = "winapi" 1120 | version = "0.3.9" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1123 | dependencies = [ 1124 | "winapi-i686-pc-windows-gnu", 1125 | "winapi-x86_64-pc-windows-gnu", 1126 | ] 1127 | 1128 | [[package]] 1129 | name = "winapi-build" 1130 | version = "0.1.1" 1131 | source = "registry+https://github.com/rust-lang/crates.io-index" 1132 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1133 | 1134 | [[package]] 1135 | name = "winapi-i686-pc-windows-gnu" 1136 | version = "0.4.0" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1139 | 1140 | [[package]] 1141 | name = "winapi-util" 1142 | version = "0.1.5" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1145 | dependencies = [ 1146 | "winapi 0.3.9", 1147 | ] 1148 | 1149 | [[package]] 1150 | name = "winapi-x86_64-pc-windows-gnu" 1151 | version = "0.4.0" 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" 1153 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1154 | 1155 | [[package]] 1156 | name = "windows-sys" 1157 | version = "0.48.0" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1160 | dependencies = [ 1161 | "windows-targets", 1162 | ] 1163 | 1164 | [[package]] 1165 | name = "windows-targets" 1166 | version = "0.48.5" 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" 1168 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1169 | dependencies = [ 1170 | "windows_aarch64_gnullvm", 1171 | "windows_aarch64_msvc", 1172 | "windows_i686_gnu", 1173 | "windows_i686_msvc", 1174 | "windows_x86_64_gnu", 1175 | "windows_x86_64_gnullvm", 1176 | "windows_x86_64_msvc", 1177 | ] 1178 | 1179 | [[package]] 1180 | name = "windows_aarch64_gnullvm" 1181 | version = "0.48.5" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1184 | 1185 | [[package]] 1186 | name = "windows_aarch64_msvc" 1187 | version = "0.48.5" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1190 | 1191 | [[package]] 1192 | name = "windows_i686_gnu" 1193 | version = "0.48.5" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1196 | 1197 | [[package]] 1198 | name = "windows_i686_msvc" 1199 | version = "0.48.5" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1202 | 1203 | [[package]] 1204 | name = "windows_x86_64_gnu" 1205 | version = "0.48.5" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1208 | 1209 | [[package]] 1210 | name = "windows_x86_64_gnullvm" 1211 | version = "0.48.5" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1214 | 1215 | [[package]] 1216 | name = "windows_x86_64_msvc" 1217 | version = "0.48.5" 1218 | source = "registry+https://github.com/rust-lang/crates.io-index" 1219 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1220 | 1221 | [[package]] 1222 | name = "ws2_32-sys" 1223 | version = "0.2.1" 1224 | source = "registry+https://github.com/rust-lang/crates.io-index" 1225 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1226 | dependencies = [ 1227 | "winapi 0.2.8", 1228 | "winapi-build", 1229 | ] 1230 | 1231 | [[package]] 1232 | name = "yansi" 1233 | version = "0.5.1" 1234 | source = "registry+https://github.com/rust-lang/crates.io-index" 1235 | checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" 1236 | --------------------------------------------------------------------------------